From 0019f868ad8dbed10fbb3c0252f4aee228f0229e Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Thu, 13 Oct 2022 19:57:56 +0200 Subject: [PATCH 001/102] Added flask support #70 --- cpl-workspace.json | 4 +- src/bot/application.py | 19 ++++++- src/bot/config/appsettings.edrafts-lapi.json | 6 +++ src/bot/config/feature-flags.json | 1 + src/bot/module_list.py | 2 + src/bot/startup.py | 4 ++ src/bot_api/__init__.py | 1 + src/bot_api/api.py | 52 +++++++++++++++++++ src/bot_api/api_module.py | 26 ++++++++++ src/bot_api/api_thread.py | 27 ++++++++++ src/bot_api/bot-api.json | 48 +++++++++++++++++ src/bot_api/controller/__init__.py | 0 src/bot_api/controller/api_controller.py | 22 ++++++++ src/bot_api/controller/api_route.py | 0 src/bot_api/logging/__init__.py | 0 src/bot_api/logging/api_logger.py | 11 ++++ src/bot_api/route/__init__.py | 0 src/bot_api/route/route.py | 11 ++++ .../configuration/feature_flags_enum.py | 2 + .../configuration/feature_flags_settings.py | 2 + 20 files changed, 235 insertions(+), 3 deletions(-) create mode 100644 src/bot_api/__init__.py create mode 100644 src/bot_api/api.py create mode 100644 src/bot_api/api_module.py create mode 100644 src/bot_api/api_thread.py create mode 100644 src/bot_api/bot-api.json create mode 100644 src/bot_api/controller/__init__.py create mode 100644 src/bot_api/controller/api_controller.py create mode 100644 src/bot_api/controller/api_route.py create mode 100644 src/bot_api/logging/__init__.py create mode 100644 src/bot_api/logging/api_logger.py create mode 100644 src/bot_api/route/__init__.py create mode 100644 src/bot_api/route/route.py diff --git a/cpl-workspace.json b/cpl-workspace.json index 9841dd57ce..82fc9abe6d 100644 --- a/cpl-workspace.json +++ b/cpl-workspace.json @@ -11,13 +11,13 @@ "boot-log": "src/modules/boot_log/boot-log.json", "database": "src/modules/database/database.json", "moderator": "src/modules/moderator/moderator.json", - "permission": "src/modules/permission/permission.json" + "permission": "src/modules/permission/permission.json", + "bot-api": "src/bot_api/bot-api.json" }, "Scripts": { "prod": "export KDB_ENVIRONMENT=production; export KDB_NAME=KDB-Prod; cpl start;", "stage": "export KDB_ENVIRONMENT=staging; export KDB_NAME=KDB-Stage; cpl start;", "dev": "export KDB_ENVIRONMENT=development; export KDB_NAME=KDB-Dev; cpl start;", - "build-docker": "cpl b; docker-compose down; docker build -t kdb .", "compose": "docker-compose up -d", "docker": "cpl build-docker; cpl compose;" diff --git a/src/bot/application.py b/src/bot/application.py index 14ce439d5d..c557eace35 100644 --- a/src/bot/application.py +++ b/src/bot/application.py @@ -7,6 +7,10 @@ from cpl_discord.configuration import DiscordBotSettings from cpl_discord.service import DiscordBotServiceABC, DiscordBotService from cpl_translation import TranslatePipe, TranslationServiceABC, TranslationSettings +from bot_api.api_thread import ApiThread +from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum +from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings + class Application(DiscordBotApplicationABC): @@ -14,6 +18,7 @@ class Application(DiscordBotApplicationABC): DiscordBotApplicationABC.__init__(self, config, services) self._services = services + self._config = config # cpl-core self._logger: LoggerABC = services.get_service(LoggerABC) @@ -24,6 +29,12 @@ class Application(DiscordBotApplicationABC): self._translation: TranslationServiceABC = services.get_service(TranslationServiceABC) self._t: TranslatePipe = services.get_service(TranslatePipe) + self._feature_flags: FeatureFlagsSettings = config.get_configuration(FeatureFlagsSettings) + + # api + if self._feature_flags.get_flag(FeatureFlagsEnum.api_module): + self._api: ApiThread = services.get_service(ApiThread) + self._is_stopping = False async def configure(self): @@ -32,6 +43,12 @@ class Application(DiscordBotApplicationABC): async def main(self): try: self._logger.debug(__name__, f'Starting...') + if self._feature_flags.get_flag(FeatureFlagsEnum.api_module): + self._api.start() + + if self._feature_flags.get_flag(FeatureFlagsEnum.api_only): + return + self._logger.trace(__name__, f'Try to start {DiscordBotService.__name__}') await self._bot.start_async() await self._bot.stop_async() @@ -53,4 +70,4 @@ class Application(DiscordBotApplicationABC): Console.write_line() def is_restart(self): - return True if self._configuration.get_configuration('IS_RESTART') == 'true' else False# + return True if self._configuration.get_configuration('IS_RESTART') == 'true' else False # diff --git a/src/bot/config/appsettings.edrafts-lapi.json b/src/bot/config/appsettings.edrafts-lapi.json index 9a4ccd18e8..2e9e52a3d7 100644 --- a/src/bot/config/appsettings.edrafts-lapi.json +++ b/src/bot/config/appsettings.edrafts-lapi.json @@ -12,6 +12,12 @@ "FileLogLevel": "TRACE" }, "BotLoggingSettings": { + "Api": { + "Path": "logs/", + "Filename": "api.log", + "ConsoleLogLevel": "TRACE", + "FileLogLevel": "TRACE" + }, "Command": { "Path": "logs/", "Filename": "commands.log", diff --git a/src/bot/config/feature-flags.json b/src/bot/config/feature-flags.json index b20c9cca8c..68bf6e002c 100644 --- a/src/bot/config/feature-flags.json +++ b/src/bot/config/feature-flags.json @@ -1,5 +1,6 @@ { "FeatureFlags": { + "ApiModule": true, "AdminModule": true, "AutoRoleModule": true, "BaseModule": true, diff --git a/src/bot/module_list.py b/src/bot/module_list.py index 5b8f4e5b61..866b7d677f 100644 --- a/src/bot/module_list.py +++ b/src/bot/module_list.py @@ -1,5 +1,6 @@ from cpl_query.extension import List +from bot_api.api_module import ApiModule from bot_core.core_extension.core_extension_module import CoreExtensionModule from bot_core.core_module import CoreModule from bot_data.data_module import DataModule @@ -20,6 +21,7 @@ class ModuleList: return List(type, [ CoreModule, # has to be first! DataModule, + ApiModule, AdminModule, AutoRoleModule, BaseModule, diff --git a/src/bot/startup.py b/src/bot/startup.py index f1c123c5b0..1384fbd9ed 100644 --- a/src/bot/startup.py +++ b/src/bot/startup.py @@ -9,6 +9,7 @@ from cpl_core.dependency_injection import ServiceProviderABC from cpl_core.environment import ApplicationEnvironment from cpl_core.logging import LoggerABC +from bot_api.logging.api_logger import ApiLogger from bot_core.abc.custom_file_logger_abc import CustomFileLoggerABC from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings @@ -40,6 +41,9 @@ class Startup(StartupABC): services.add_singleton(CustomFileLoggerABC, DatabaseLogger) services.add_singleton(CustomFileLoggerABC, MessageLogger) + if self._feature_flags.get_flag(FeatureFlagsEnum.api_module): + services.add_singleton(CustomFileLoggerABC, ApiLogger) + services.add_translation() services.add_db_context(DBContext, self._config.get_configuration(DatabaseSettings)) diff --git a/src/bot_api/__init__.py b/src/bot_api/__init__.py new file mode 100644 index 0000000000..ad5eca3064 --- /dev/null +++ b/src/bot_api/__init__.py @@ -0,0 +1 @@ +# imports: diff --git a/src/bot_api/api.py b/src/bot_api/api.py new file mode 100644 index 0000000000..7a75e2a497 --- /dev/null +++ b/src/bot_api/api.py @@ -0,0 +1,52 @@ +import sys +from functools import partial + +from cpl_core.dependency_injection import ServiceProviderABC +from flask import Flask, request + +from bot_api.logging.api_logger import ApiLogger +from bot_api.route.route import Route + + +class Api(Flask): + + def __init__( + self, + logger: ApiLogger, + services: ServiceProviderABC, + *args, **kwargs + ): + if not args: + kwargs.setdefault('import_name', __name__) + + Flask.__init__(self, *args, **kwargs) + + self._logger = logger + self._services = services + + # register before request + self.before_request_funcs.setdefault(None, []).append(self.before_request) + + def _register_routes(self): + for path, f in Route.registered_routes.items(): + cls = None + qual_name_split = f.__qualname__.split('.') + if len(qual_name_split) > 0: + cls_type = vars(sys.modules[f.__module__])[qual_name_split[0]] + cls = self._services.get_service(cls_type) + + partial_f = partial(f, self if cls is None else cls) + partial_f.__name__ = f.__name__ + self.route(path)(partial_f) + + def before_request(self, *args, **kwargs): + self._logger.debug(__name__, f'Received GET @{request.url}') + headers = str(request.headers).replace("\n", "\n\t") + self._logger.trace(__name__, f'Headers: \n\t{headers}') + self._logger.trace(__name__, f'Body: {request.get_json(force=True, silent=True)}') + + def start(self): + self._logger.info(__name__, f'Starting API') + self._register_routes() + from waitress import serve + serve(self, host="0.0.0.0", port=5000) diff --git a/src/bot_api/api_module.py b/src/bot_api/api_module.py new file mode 100644 index 0000000000..91f91794d4 --- /dev/null +++ b/src/bot_api/api_module.py @@ -0,0 +1,26 @@ +from cpl_core.configuration import ConfigurationABC +from cpl_core.dependency_injection import ServiceCollectionABC +from cpl_core.environment import ApplicationEnvironmentABC +from cpl_discord.service.discord_collection_abc import DiscordCollectionABC +from flask import Flask + +from bot_api.api import Api +from bot_api.api_thread import ApiThread +from bot_api.controller.api_controller import ApiController +from bot_core.abc.module_abc import ModuleABC +from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum + + +class ApiModule(ModuleABC): + + def __init__(self, dc: DiscordCollectionABC): + ModuleABC.__init__(self, dc, FeatureFlagsEnum.api_module) + + def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC): + pass + + def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC): + services.add_singleton(ApiThread) + services.add_singleton(Flask, Api) + + services.add_transient(ApiController) diff --git a/src/bot_api/api_thread.py b/src/bot_api/api_thread.py new file mode 100644 index 0000000000..b6a34bde4d --- /dev/null +++ b/src/bot_api/api_thread.py @@ -0,0 +1,27 @@ +import threading + +from bot_api.api import Api +from bot_api.logging.api_logger import ApiLogger +from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum +from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings + + +class ApiThread(threading.Thread): + + def __init__( + self, + logger: ApiLogger, + api: Api, + feature_flags: FeatureFlagsSettings + ): + threading.Thread.__init__(self, daemon=not feature_flags.get_flag(FeatureFlagsEnum.api_only)) + + self._logger = logger + self._api = api + + def run(self) -> None: + try: + self._logger.trace(__name__, f'Try to start {type(self._api).__name__}') + self._api.start() + except Exception as e: + self._logger.error(__name__, 'Start failed', e) diff --git a/src/bot_api/bot-api.json b/src/bot_api/bot-api.json new file mode 100644 index 0000000000..b31234fd9b --- /dev/null +++ b/src/bot_api/bot-api.json @@ -0,0 +1,48 @@ +{ + "ProjectSettings": { + "Name": "bot-api", + "Version": { + "Major": "0", + "Minor": "0", + "Micro": "0" + }, + "Author": "", + "AuthorEmail": "", + "Description": "", + "LongDescription": "", + "URL": "", + "CopyrightDate": "", + "CopyrightName": "", + "LicenseName": "", + "LicenseDescription": "", + "Dependencies": [ + "cpl-core==2022.10.0.post6", + "Flask==2.2.2", + "Flask-Classful==0.14.2" + ], + "DevDependencies": [ + "cpl-cli>=2022.10.0" + ], + "PythonVersion": ">=3.10.4", + "PythonPath": { + "linux": "" + }, + "Classifiers": [] + }, + "BuildSettings": { + "ProjectType": "library", + "SourcePath": "", + "OutputPath": "../../dist", + "Main": "bot_api.main", + "EntryPoint": "bot-api", + "IncludePackageData": false, + "Included": [], + "Excluded": [ + "*/__pycache__", + "*/logs", + "*/tests" + ], + "PackageData": {}, + "ProjectReferences": [] + } +} \ No newline at end of file diff --git a/src/bot_api/controller/__init__.py b/src/bot_api/controller/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/bot_api/controller/api_controller.py b/src/bot_api/controller/api_controller.py new file mode 100644 index 0000000000..9c71416678 --- /dev/null +++ b/src/bot_api/controller/api_controller.py @@ -0,0 +1,22 @@ +from cpl_translation import TranslatePipe + +from bot_api.api import Api +from bot_api.logging.api_logger import ApiLogger +from bot_api.route.route import Route + + +class ApiController: + + def __init__( + self, + logger: ApiLogger, + t: TranslatePipe, + api: Api + ): + self._logger = logger + self._t = t + self._api = api + + @Route.route('/api/hello-world') + def hello_world(self): + return self._t.transform('common.hello_world') diff --git a/src/bot_api/controller/api_route.py b/src/bot_api/controller/api_route.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/bot_api/logging/__init__.py b/src/bot_api/logging/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/bot_api/logging/api_logger.py b/src/bot_api/logging/api_logger.py new file mode 100644 index 0000000000..1e4f00e82f --- /dev/null +++ b/src/bot_api/logging/api_logger.py @@ -0,0 +1,11 @@ +from cpl_core.configuration import ConfigurationABC +from cpl_core.environment import ApplicationEnvironmentABC +from cpl_core.time import TimeFormatSettings + +from bot_core.abc.custom_file_logger_abc import CustomFileLoggerABC + + +class ApiLogger(CustomFileLoggerABC): + + def __init__(self, config: ConfigurationABC, time_format: TimeFormatSettings, env: ApplicationEnvironmentABC): + CustomFileLoggerABC.__init__(self, 'Api', config, time_format, env) diff --git a/src/bot_api/route/__init__.py b/src/bot_api/route/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/bot_api/route/route.py b/src/bot_api/route/route.py new file mode 100644 index 0000000000..ef0e399403 --- /dev/null +++ b/src/bot_api/route/route.py @@ -0,0 +1,11 @@ +class Route: + registered_routes = {} + + @classmethod + def route(cls, path=None): + # simple decorator for class based views + def inner(fn): + cls.registered_routes[path] = fn + return fn + + return inner diff --git a/src/bot_core/configuration/feature_flags_enum.py b/src/bot_core/configuration/feature_flags_enum.py index dac193b141..b41ec6e53e 100644 --- a/src/bot_core/configuration/feature_flags_enum.py +++ b/src/bot_core/configuration/feature_flags_enum.py @@ -4,6 +4,7 @@ from enum import Enum class FeatureFlagsEnum(Enum): # modules + api_module = 'ApiModule' admin_module = 'AdminModule' auto_role_module = 'AutoRoleModule' base_module = 'BaseModule' @@ -15,4 +16,5 @@ class FeatureFlagsEnum(Enum): moderator_module = 'ModeratorModule' permission_module = 'PermissionModule' # features + api_only = 'ApiOnly' presence = 'Presence' diff --git a/src/bot_core/configuration/feature_flags_settings.py b/src/bot_core/configuration/feature_flags_settings.py index 4556e78481..1861f9a115 100644 --- a/src/bot_core/configuration/feature_flags_settings.py +++ b/src/bot_core/configuration/feature_flags_settings.py @@ -14,6 +14,7 @@ class FeatureFlagsSettings(ConfigurationModelABC): self._flags = { # modules + FeatureFlagsEnum.api_module.value: False, # 13.10.2022 #70 FeatureFlagsEnum.admin_module.value: False, # 02.10.2022 #48 FeatureFlagsEnum.auto_role_module.value: True, # 03.10.2022 #54 FeatureFlagsEnum.base_module.value: True, # 02.10.2022 #48 @@ -25,6 +26,7 @@ class FeatureFlagsSettings(ConfigurationModelABC): FeatureFlagsEnum.moderator_module.value: False, # 02.10.2022 #48 FeatureFlagsEnum.permission_module.value: True, # 02.10.2022 #48 # features + FeatureFlagsEnum.api_only.value: False, # 13.10.2022 #70 FeatureFlagsEnum.presence.value: True, # 03.10.2022 #56 } From 0927288bb5d0f237bc528dc33efc3492471ae895 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Thu, 13 Oct 2022 20:57:47 +0200 Subject: [PATCH 002/102] Added api calls #70 --- src/bot/bot.json | 1 + src/bot/translation/de.json | 8 +++ src/bot_api/__init__.py | 25 +++++++ src/bot_api/abc/__init__.py | 26 +++++++ src/bot_api/abc/dto_abc.py | 13 ++++ src/bot_api/api_module.py | 12 +++- .../config/apisettings.development.json | 8 +++ .../config/apisettings.edrafts-lapi.json | 1 + .../config/apisettings.edrafts-pc-ubuntu.json | 1 + src/bot_api/config/apisettings.json | 1 + .../config/apisettings.production.json | 1 + src/bot_api/config/apisettings.staging.json | 1 + src/bot_api/config/appsettings.PC-Nick.json | 1 + src/bot_api/configuration/__init__.py | 1 + src/bot_api/configuration/api_settings.py | 23 ++++++ src/bot_api/configuration/version_settings.py | 55 ++++++++++++++ src/bot_api/controller/__init__.py | 26 +++++++ src/bot_api/controller/api_controller.py | 58 +++++++++++++-- src/bot_api/controller/api_route.py | 0 src/bot_api/logging/__init__.py | 26 +++++++ src/bot_api/model/__init__.py | 26 +++++++ src/bot_api/model/settings_dto.py | 71 +++++++++++++++++++ src/bot_api/model/version_dto.py | 27 +++++++ src/bot_api/route/__init__.py | 26 +++++++ 24 files changed, 433 insertions(+), 5 deletions(-) create mode 100644 src/bot_api/abc/__init__.py create mode 100644 src/bot_api/abc/dto_abc.py create mode 100644 src/bot_api/config/apisettings.development.json create mode 100644 src/bot_api/config/apisettings.edrafts-lapi.json create mode 100644 src/bot_api/config/apisettings.edrafts-pc-ubuntu.json create mode 100644 src/bot_api/config/apisettings.json create mode 100644 src/bot_api/config/apisettings.production.json create mode 100644 src/bot_api/config/apisettings.staging.json create mode 100644 src/bot_api/config/appsettings.PC-Nick.json create mode 100644 src/bot_api/configuration/__init__.py create mode 100644 src/bot_api/configuration/api_settings.py create mode 100644 src/bot_api/configuration/version_settings.py delete mode 100644 src/bot_api/controller/api_route.py create mode 100644 src/bot_api/model/__init__.py create mode 100644 src/bot_api/model/settings_dto.py create mode 100644 src/bot_api/model/version_dto.py diff --git a/src/bot/bot.json b/src/bot/bot.json index 8bbcdf43bb..64495674d9 100644 --- a/src/bot/bot.json +++ b/src/bot/bot.json @@ -45,6 +45,7 @@ ], "PackageData": {}, "ProjectReferences": [ + "../bot_api/bot-api.json", "../bot_core/bot-core.json", "../bot_data/bot-data.json", "../modules/base/base.json", diff --git a/src/bot/translation/de.json b/src/bot/translation/de.json index 910de71752..03b69e95c9 100644 --- a/src/bot/translation/de.json +++ b/src/bot/translation/de.json @@ -152,5 +152,13 @@ "database": {}, "permission": { } + }, + "api": { + "api": { + "test_mail": { + "subject": "Krümmelmonster Web Interface Test-Mail", + "message": "Dies ist eine Test-Mail vom Krümmelmonster Web Interface\nGesendet von {}-{}" + } + } } } \ No newline at end of file diff --git a/src/bot_api/__init__.py b/src/bot_api/__init__.py index ad5eca3064..99097c738a 100644 --- a/src/bot_api/__init__.py +++ b/src/bot_api/__init__.py @@ -1 +1,26 @@ +# -*- coding: utf-8 -*- + +""" +bot Keksdose bot +~~~~~~~~~~~~~~~~~~~ + +Discord bot for the Keksdose discord Server + +:copyright: (c) 2022 sh-edraft.de +:license: MIT, see LICENSE for more details. + +""" + +__title__ = 'bot_api' +__author__ = 'Sven Heidemann' +__license__ = 'MIT' +__copyright__ = 'Copyright (c) 2022 sh-edraft.de' +__version__ = '0.2.3' + +from collections import namedtuple + + # imports: + +VersionInfo = namedtuple('VersionInfo', 'major minor micro') +version_info = VersionInfo(major='0', minor='2', micro='3') diff --git a/src/bot_api/abc/__init__.py b/src/bot_api/abc/__init__.py new file mode 100644 index 0000000000..38bf68b7f9 --- /dev/null +++ b/src/bot_api/abc/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +""" +bot Keksdose bot +~~~~~~~~~~~~~~~~~~~ + +Discord bot for the Keksdose discord Server + +:copyright: (c) 2022 sh-edraft.de +:license: MIT, see LICENSE for more details. + +""" + +__title__ = 'bot_api.abc' +__author__ = 'Sven Heidemann' +__license__ = 'MIT' +__copyright__ = 'Copyright (c) 2022 sh-edraft.de' +__version__ = '0.2.3' + +from collections import namedtuple + + +# imports: + +VersionInfo = namedtuple('VersionInfo', 'major minor micro') +version_info = VersionInfo(major='0', minor='2', micro='3') diff --git a/src/bot_api/abc/dto_abc.py b/src/bot_api/abc/dto_abc.py new file mode 100644 index 0000000000..58b458ad8a --- /dev/null +++ b/src/bot_api/abc/dto_abc.py @@ -0,0 +1,13 @@ +from abc import ABC, abstractmethod + + +class DtoABC(ABC): + + @abstractmethod + def __init__(self): pass + + @abstractmethod + def from_dict(self, values: dict): pass + + @abstractmethod + def to_dict(self) -> dict: pass diff --git a/src/bot_api/api_module.py b/src/bot_api/api_module.py index 91f91794d4..3f26d80c56 100644 --- a/src/bot_api/api_module.py +++ b/src/bot_api/api_module.py @@ -1,6 +1,9 @@ +import os + from cpl_core.configuration import ConfigurationABC from cpl_core.dependency_injection import ServiceCollectionABC from cpl_core.environment import ApplicationEnvironmentABC +from cpl_core.mailing import EMailClientABC, EMailClient from cpl_discord.service.discord_collection_abc import DiscordCollectionABC from flask import Flask @@ -17,9 +20,16 @@ class ApiModule(ModuleABC): ModuleABC.__init__(self, dc, FeatureFlagsEnum.api_module) def configure_configuration(self, config: ConfigurationABC, env: ApplicationEnvironmentABC): - pass + cwd = env.working_directory + env.set_working_directory(os.path.dirname(os.path.realpath(__file__))) + config.add_json_file(f'config/apisettings.json', optional=False) + config.add_json_file(f'config/apisettings.{env.environment_name}.json', optional=True) + config.add_json_file(f'config/apisettings.{env.host_name}.json', optional=True) + env.set_working_directory(cwd) def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC): + services.add_singleton(EMailClientABC, EMailClient) + services.add_singleton(ApiThread) services.add_singleton(Flask, Api) diff --git a/src/bot_api/config/apisettings.development.json b/src/bot_api/config/apisettings.development.json new file mode 100644 index 0000000000..534e5087be --- /dev/null +++ b/src/bot_api/config/apisettings.development.json @@ -0,0 +1,8 @@ +{ + "EMailClientSettings": { + "Host": "mail.sh-edraft.de", + "Port": "587", + "UserName": "dev-srv@sh-edraft.de", + "Credentials": "RmBOQX1eNFYiYjgsSid3fV1nelc2WA==" + } +} \ No newline at end of file diff --git a/src/bot_api/config/apisettings.edrafts-lapi.json b/src/bot_api/config/apisettings.edrafts-lapi.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/src/bot_api/config/apisettings.edrafts-lapi.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/bot_api/config/apisettings.edrafts-pc-ubuntu.json b/src/bot_api/config/apisettings.edrafts-pc-ubuntu.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/src/bot_api/config/apisettings.edrafts-pc-ubuntu.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/bot_api/config/apisettings.json b/src/bot_api/config/apisettings.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/src/bot_api/config/apisettings.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/bot_api/config/apisettings.production.json b/src/bot_api/config/apisettings.production.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/src/bot_api/config/apisettings.production.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/bot_api/config/apisettings.staging.json b/src/bot_api/config/apisettings.staging.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/src/bot_api/config/apisettings.staging.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/bot_api/config/appsettings.PC-Nick.json b/src/bot_api/config/appsettings.PC-Nick.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/src/bot_api/config/appsettings.PC-Nick.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/bot_api/configuration/__init__.py b/src/bot_api/configuration/__init__.py new file mode 100644 index 0000000000..425ab6c146 --- /dev/null +++ b/src/bot_api/configuration/__init__.py @@ -0,0 +1 @@ +# imports diff --git a/src/bot_api/configuration/api_settings.py b/src/bot_api/configuration/api_settings.py new file mode 100644 index 0000000000..e50f25fa95 --- /dev/null +++ b/src/bot_api/configuration/api_settings.py @@ -0,0 +1,23 @@ +import traceback + +from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC +from cpl_core.console import Console + + +class APISettings(ConfigurationModelABC): + + def __init__(self): + ConfigurationModelABC.__init__(self) + + self._redirect_to_https = False + + @property + def redirect_to_https(self) -> bool: + return self._redirect_to_https + + def from_dict(self, settings: dict): + try: + self._redirect_to_https = bool(settings['RedirectToHTTPS']) + except Exception as e: + Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings') + Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}') diff --git a/src/bot_api/configuration/version_settings.py b/src/bot_api/configuration/version_settings.py new file mode 100644 index 0000000000..ef1af9b6c2 --- /dev/null +++ b/src/bot_api/configuration/version_settings.py @@ -0,0 +1,55 @@ +from typing import Optional + +from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC +from cpl_cli.configuration.version_settings_name_enum import VersionSettingsNameEnum + + +class VersionSettings(ConfigurationModelABC): + + def __init__( + self, + major: str = None, + minor: str = None, + micro: str = None + ): + ConfigurationModelABC.__init__(self) + + self._major: Optional[str] = major + self._minor: Optional[str] = minor + self._micro: Optional[str] = micro + + @property + def major(self) -> str: + return self._major + + @property + def minor(self) -> str: + return self._minor + + @property + def micro(self) -> str: + return self._micro + + def to_str(self) -> str: + if self._micro is None: + return f'{self._major}.{self._minor}' + else: + return f'{self._major}.{self._minor}.{self._micro}' + + def from_dict(self, settings: dict): + self._major = settings[VersionSettingsNameEnum.major.value] + self._minor = settings[VersionSettingsNameEnum.minor.value] + micro = settings[VersionSettingsNameEnum.micro.value] + if micro != '': + self._micro = micro + + def to_dict(self) -> dict: + version = { + VersionSettingsNameEnum.major.value: self._major, + VersionSettingsNameEnum.minor.value: self._minor, + } + + if self._micro is not None: + version[VersionSettingsNameEnum.micro.value] = self._micro + + return version diff --git a/src/bot_api/controller/__init__.py b/src/bot_api/controller/__init__.py index e69de29bb2..44c37e5c00 100644 --- a/src/bot_api/controller/__init__.py +++ b/src/bot_api/controller/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +""" +bot Keksdose bot +~~~~~~~~~~~~~~~~~~~ + +Discord bot for the Keksdose discord Server + +:copyright: (c) 2022 sh-edraft.de +:license: MIT, see LICENSE for more details. + +""" + +__title__ = 'bot_api.controller' +__author__ = 'Sven Heidemann' +__license__ = 'MIT' +__copyright__ = 'Copyright (c) 2022 sh-edraft.de' +__version__ = '0.2.3' + +from collections import namedtuple + + +# imports: + +VersionInfo = namedtuple('VersionInfo', 'major minor micro') +version_info = VersionInfo(major='0', minor='2', micro='3') diff --git a/src/bot_api/controller/api_controller.py b/src/bot_api/controller/api_controller.py index 9c71416678..e17103e6dd 100644 --- a/src/bot_api/controller/api_controller.py +++ b/src/bot_api/controller/api_controller.py @@ -1,7 +1,14 @@ +import os + +from cpl_core.configuration import ConfigurationABC +from cpl_core.environment import ApplicationEnvironmentABC +from cpl_core.mailing import EMail, EMailClientABC, EMailClientSettings from cpl_translation import TranslatePipe from bot_api.api import Api from bot_api.logging.api_logger import ApiLogger +from bot_api.model.settings_dto import SettingsDTO +from bot_api.model.version_dto import VersionDTO from bot_api.route.route import Route @@ -9,14 +16,57 @@ class ApiController: def __init__( self, + config: ConfigurationABC, + env: ApplicationEnvironmentABC, logger: ApiLogger, t: TranslatePipe, - api: Api + api: Api, + mail_settings: EMailClientSettings, + mailer: EMailClientABC ): + self._config = config + self._env = env self._logger = logger self._t = t self._api = api + self._mail_settings = mail_settings + self._mailer = mailer - @Route.route('/api/hello-world') - def hello_world(self): - return self._t.transform('common.hello_world') + @Route.route('/api/api-version') + def api_version(self): + import bot_api + version = bot_api.version_info + return VersionDTO(version.major, version.minor, version.micro).to_dict() + + @Route.route('/api/settings') + def settings(self): + # TODO: Authentication + import bot_api + version = bot_api.version_info + + return SettingsDTO( + '', + VersionDTO(version.major, version.minor, version.micro), + os.path.abspath(os.path.join(self._env.working_directory, 'config')), + '', + '/', + 0, + 0, + self._mail_settings.user_name, + self._mail_settings.port, + self._mail_settings.host, + self._mail_settings.user_name, + self._mail_settings.user_name, + ).to_dict() + + @Route.route('/api/send-test-mail/') + def send_test_mail(self, email: str): + # TODO: Authentication + mail = EMail() + mail.add_header('Mime-Version: 1.0') + mail.add_header('Content-Type: text/plain; charset=utf-8') + mail.add_header('Content-Transfer-Encoding: quoted-printable') + mail.add_receiver(email) + mail.subject = self._t.transform('api.api.test_mail.subject') + mail.body = self._t.transform('api.api.test_mail.message').format(self._env.host_name, self._env.environment_name) + self._mailer.send_mail(mail) diff --git a/src/bot_api/controller/api_route.py b/src/bot_api/controller/api_route.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/bot_api/logging/__init__.py b/src/bot_api/logging/__init__.py index e69de29bb2..d7b9d180c4 100644 --- a/src/bot_api/logging/__init__.py +++ b/src/bot_api/logging/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +""" +bot Keksdose bot +~~~~~~~~~~~~~~~~~~~ + +Discord bot for the Keksdose discord Server + +:copyright: (c) 2022 sh-edraft.de +:license: MIT, see LICENSE for more details. + +""" + +__title__ = 'bot_api.logging' +__author__ = 'Sven Heidemann' +__license__ = 'MIT' +__copyright__ = 'Copyright (c) 2022 sh-edraft.de' +__version__ = '0.2.3' + +from collections import namedtuple + + +# imports: + +VersionInfo = namedtuple('VersionInfo', 'major minor micro') +version_info = VersionInfo(major='0', minor='2', micro='3') diff --git a/src/bot_api/model/__init__.py b/src/bot_api/model/__init__.py new file mode 100644 index 0000000000..da73f2230b --- /dev/null +++ b/src/bot_api/model/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +""" +bot Keksdose bot +~~~~~~~~~~~~~~~~~~~ + +Discord bot for the Keksdose discord Server + +:copyright: (c) 2022 sh-edraft.de +:license: MIT, see LICENSE for more details. + +""" + +__title__ = 'bot_api.model' +__author__ = 'Sven Heidemann' +__license__ = 'MIT' +__copyright__ = 'Copyright (c) 2022 sh-edraft.de' +__version__ = '0.2.3' + +from collections import namedtuple + + +# imports: + +VersionInfo = namedtuple('VersionInfo', 'major minor micro') +version_info = VersionInfo(major='0', minor='2', micro='3') diff --git a/src/bot_api/model/settings_dto.py b/src/bot_api/model/settings_dto.py new file mode 100644 index 0000000000..6d72245ba2 --- /dev/null +++ b/src/bot_api/model/settings_dto.py @@ -0,0 +1,71 @@ +import traceback + +from cpl_core.console import Console + +from bot_api.abc.dto_abc import DtoABC +from bot_api.model.version_dto import VersionDTO + + +class SettingsDTO(DtoABC): + + def __init__( + self, + web_version: str, + api_version: VersionDTO, + config_path: str, + web_base_url: str, + api_base_url: str, + token_expire_time: int, + refresh_token_expire_time: int, + mail_user: str, + mail_port: int, + mail_host: str, + mail_transceiver: str, + mail_transceiver_address: str, + ): + DtoABC.__init__(self) + + self._web_version = '' + self._api_version = VersionDTO() + self._config_path = '' + self._web_base_url = '' + self._api_base_url = '' + + self._token_expire_time = 0 + self._refresh_token_expire_time = 0 + + self._mail_user = '' + self._mail_port = 0 + self._mail_host = '' + self._mail_transceiver = '' + self._mail_transceiver_address = '' + + def from_dict(self, values: dict): + self._web_version = values['WebVersion'] + self._api_version.from_dict(values['ApiVersion']) + self._config_path = values['ConfigPath'] + self._web_base_url = values['WebBaseURL'] + self._api_base_url = values['ApiBaseURL'] + self._token_expire_time = values['TokenExpireTime'] + self._refresh_token_expire_time = values['RefreshTokenExpireTime'] + self._mail_user = values['MailUser'] + self._mail_port = values['MailPort'] + self._mail_host = values['MailHost'] + self._mail_transceiver = values['MailTransceiver'] + self._mail_transceiver_address = values['MailTransceiverAddress'] + + def to_dict(self) -> dict: + return { + 'WebVersion': self._web_version, + 'ApiVersion': self._api_version.to_dict(), + 'ConfigPath': self._config_path, + 'WebBaseURL': self._web_base_url, + 'ApiBaseURL': self._api_base_url, + 'TokenExpireTime': self._token_expire_time, + 'RefreshTokenExpireTime': self._refresh_token_expire_time, + 'MailUser': self._mail_user, + 'MailPort': self._mail_port, + 'MailHost': self._mail_host, + 'MailTransceiver': self._mail_transceiver, + 'MailTransceiverAddress': self._mail_transceiver_address, + } diff --git a/src/bot_api/model/version_dto.py b/src/bot_api/model/version_dto.py new file mode 100644 index 0000000000..8ef98dc401 --- /dev/null +++ b/src/bot_api/model/version_dto.py @@ -0,0 +1,27 @@ +import traceback + +from cpl_core.console import Console + +from bot_api.abc.dto_abc import DtoABC + + +class VersionDTO(DtoABC): + + def __init__(self, major: str = None, minor: str = None, micro: str = None): + DtoABC.__init__(self) + + self._major = major + self._minor = minor + self._micro = micro + + def from_dict(self, values: dict): + self._major = values['Major'] + self._minor = values['Minor'] + self._micro = values['Micro'] + + def to_dict(self) -> dict: + return { + 'Major': self._major, + 'Minor': self._minor, + 'Micro': self._micro, + } diff --git a/src/bot_api/route/__init__.py b/src/bot_api/route/__init__.py index e69de29bb2..3f08538e82 100644 --- a/src/bot_api/route/__init__.py +++ b/src/bot_api/route/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +""" +bot Keksdose bot +~~~~~~~~~~~~~~~~~~~ + +Discord bot for the Keksdose discord Server + +:copyright: (c) 2022 sh-edraft.de +:license: MIT, see LICENSE for more details. + +""" + +__title__ = 'bot_api.route' +__author__ = 'Sven Heidemann' +__license__ = 'MIT' +__copyright__ = 'Copyright (c) 2022 sh-edraft.de' +__version__ = '0.2.3' + +from collections import namedtuple + + +# imports: + +VersionInfo = namedtuple('VersionInfo', 'major minor micro') +version_info = VersionInfo(major='0', minor='2', micro='3') From aab3d6236533282517d9fc58a844b738c35a904d Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Fri, 14 Oct 2022 07:04:56 +0200 Subject: [PATCH 003/102] Added api settings #70 --- src/bot/config/feature-flags.json | 3 +- src/bot_api/api.py | 7 ++- .../config/apisettings.edrafts-lapi.json | 18 ++++++- src/bot_api/configuration/api_settings.py | 14 +++++- .../configuration/authentication_settings.py | 48 +++++++++++++++++++ .../configuration/frontend_settings.py | 23 +++++++++ 6 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 src/bot_api/configuration/authentication_settings.py create mode 100644 src/bot_api/configuration/frontend_settings.py diff --git a/src/bot/config/feature-flags.json b/src/bot/config/feature-flags.json index 68bf6e002c..2d214f7f3e 100644 --- a/src/bot/config/feature-flags.json +++ b/src/bot/config/feature-flags.json @@ -10,6 +10,7 @@ "DatabaseModule": true, "ModeratorModule": true, "PermissionModule": true, - "PresenceModule": true + "PresenceModule": true, + "ApiOnly": true } } diff --git a/src/bot_api/api.py b/src/bot_api/api.py index 7a75e2a497..c404350521 100644 --- a/src/bot_api/api.py +++ b/src/bot_api/api.py @@ -4,6 +4,7 @@ from functools import partial from cpl_core.dependency_injection import ServiceProviderABC from flask import Flask, request +from bot_api.configuration.api_settings import ApiSettings from bot_api.logging.api_logger import ApiLogger from bot_api.route.route import Route @@ -14,6 +15,7 @@ class Api(Flask): self, logger: ApiLogger, services: ServiceProviderABC, + api_settings: ApiSettings, *args, **kwargs ): if not args: @@ -23,6 +25,7 @@ class Api(Flask): self._logger = logger self._services = services + self._apt_settings = api_settings # register before request self.before_request_funcs.setdefault(None, []).append(self.before_request) @@ -46,7 +49,7 @@ class Api(Flask): self._logger.trace(__name__, f'Body: {request.get_json(force=True, silent=True)}') def start(self): - self._logger.info(__name__, f'Starting API') + self._logger.info(__name__, f'Starting API {self._apt_settings.host}:{self._apt_settings.port}') self._register_routes() from waitress import serve - serve(self, host="0.0.0.0", port=5000) + serve(self, host=self._apt_settings.host, port=self._apt_settings.port) diff --git a/src/bot_api/config/apisettings.edrafts-lapi.json b/src/bot_api/config/apisettings.edrafts-lapi.json index 9e26dfeeb6..fb7c257c3b 100644 --- a/src/bot_api/config/apisettings.edrafts-lapi.json +++ b/src/bot_api/config/apisettings.edrafts-lapi.json @@ -1 +1,17 @@ -{} \ No newline at end of file +{ + "Api": { + "Port": 5000, + "Host": "0.0.0.0", + "RedirectToHTTPS": false + }, + "Authentication": { + "SecretKey": "F3b5LDz+#Jvzg=W!@gsa%xsF", + "Issuer": "http://localhost:5000", + "Audience": "http://localhost:5000", + "TokenExpireTime": 1, + "RefreshTokenExpireTime": 7 + }, + "Frontend": { + "URL": "http://localhost:4200/" + } +} \ No newline at end of file diff --git a/src/bot_api/configuration/api_settings.py b/src/bot_api/configuration/api_settings.py index e50f25fa95..237a272e19 100644 --- a/src/bot_api/configuration/api_settings.py +++ b/src/bot_api/configuration/api_settings.py @@ -4,19 +4,31 @@ from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC from cpl_core.console import Console -class APISettings(ConfigurationModelABC): +class ApiSettings(ConfigurationModelABC): def __init__(self): ConfigurationModelABC.__init__(self) + self._port = 80 + self._host = '' self._redirect_to_https = False + @property + def port(self) -> int: + return self._port + + @property + def host(self) -> str: + return self._host + @property def redirect_to_https(self) -> bool: return self._redirect_to_https def from_dict(self, settings: dict): try: + self._port = int(settings['Port']) + self._host = settings['Host'] self._redirect_to_https = bool(settings['RedirectToHTTPS']) except Exception as e: Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings') diff --git a/src/bot_api/configuration/authentication_settings.py b/src/bot_api/configuration/authentication_settings.py new file mode 100644 index 0000000000..9a573a8b79 --- /dev/null +++ b/src/bot_api/configuration/authentication_settings.py @@ -0,0 +1,48 @@ +import traceback +from datetime import datetime + +from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC +from cpl_core.console import Console + + +class AuthenticationSettings(ConfigurationModelABC): + + def __init__(self): + ConfigurationModelABC.__init__(self) + + self._secret_key = '' + self._issuer = '' + self._audience = '' + self._token_expire_time = 0 + self._refresh_token_expire_time = 0 + + @property + def secret_key(self) -> str: + return self._secret_key + + @property + def issuer(self) -> str: + return self._issuer + + @property + def audience(self) -> str: + return self._audience + + @property + def token_expire_time(self) -> int: + return self._token_expire_time + + @property + def refresh_token_expire_time(self) -> int: + return self._refresh_token_expire_time + + def from_dict(self, settings: dict): + try: + self._secret_key = settings['SecretKey'] + self._issuer = settings['Issuer'] + self._audience = settings['Audience'] + self._token_expire_time = int(settings['TokenExpireTime']) + self._refresh_token_expire_time = int(settings['RefreshTokenExpireTime']) + except Exception as e: + Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings') + Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}') diff --git a/src/bot_api/configuration/frontend_settings.py b/src/bot_api/configuration/frontend_settings.py new file mode 100644 index 0000000000..2090f5a237 --- /dev/null +++ b/src/bot_api/configuration/frontend_settings.py @@ -0,0 +1,23 @@ +import traceback + +from cpl_core.configuration.configuration_model_abc import ConfigurationModelABC +from cpl_core.console import Console + + +class FrontendSettings(ConfigurationModelABC): + + def __init__(self): + ConfigurationModelABC.__init__(self) + + self._url = '' + + @property + def url(self) -> str: + return self._url + + def from_dict(self, settings: dict): + try: + self._url = settings['URL'] + except Exception as e: + Console.error(f'[ ERROR ] [ {__name__} ]: Reading error in {type(self).__name__} settings') + Console.error(f'[ EXCEPTION ] [ {__name__} ]: {e} -> {traceback.format_exc()}') From e8c491a47836ff6185e402a72dd43d70bafd292a Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Fri, 14 Oct 2022 07:16:12 +0200 Subject: [PATCH 004/102] Made api async #70 --- src/bot/application.py | 1 + src/bot_api/api_thread.py | 2 +- src/bot_api/bot-api.json | 2 +- src/bot_api/controller/api_controller.py | 6 +++--- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/bot/application.py b/src/bot/application.py index c557eace35..726cdbdbf0 100644 --- a/src/bot/application.py +++ b/src/bot/application.py @@ -47,6 +47,7 @@ class Application(DiscordBotApplicationABC): self._api.start() if self._feature_flags.get_flag(FeatureFlagsEnum.api_only): + self._api.join() return self._logger.trace(__name__, f'Try to start {DiscordBotService.__name__}') diff --git a/src/bot_api/api_thread.py b/src/bot_api/api_thread.py index b6a34bde4d..f3ecf6cc76 100644 --- a/src/bot_api/api_thread.py +++ b/src/bot_api/api_thread.py @@ -14,7 +14,7 @@ class ApiThread(threading.Thread): api: Api, feature_flags: FeatureFlagsSettings ): - threading.Thread.__init__(self, daemon=not feature_flags.get_flag(FeatureFlagsEnum.api_only)) + threading.Thread.__init__(self, daemon=True) self._logger = logger self._api = api diff --git a/src/bot_api/bot-api.json b/src/bot_api/bot-api.json index b31234fd9b..09e4129308 100644 --- a/src/bot_api/bot-api.json +++ b/src/bot_api/bot-api.json @@ -17,7 +17,7 @@ "LicenseDescription": "", "Dependencies": [ "cpl-core==2022.10.0.post6", - "Flask==2.2.2", + "Flask[async]==2.2.2", "Flask-Classful==0.14.2" ], "DevDependencies": [ diff --git a/src/bot_api/controller/api_controller.py b/src/bot_api/controller/api_controller.py index e17103e6dd..1b7ae669d2 100644 --- a/src/bot_api/controller/api_controller.py +++ b/src/bot_api/controller/api_controller.py @@ -33,13 +33,13 @@ class ApiController: self._mailer = mailer @Route.route('/api/api-version') - def api_version(self): + async def api_version(self): import bot_api version = bot_api.version_info return VersionDTO(version.major, version.minor, version.micro).to_dict() @Route.route('/api/settings') - def settings(self): + async def settings(self): # TODO: Authentication import bot_api version = bot_api.version_info @@ -60,7 +60,7 @@ class ApiController: ).to_dict() @Route.route('/api/send-test-mail/') - def send_test_mail(self, email: str): + async def send_test_mail(self, email: str): # TODO: Authentication mail = EMail() mail.add_header('Mime-Version: 1.0') From 91b054fdca1ccd677c952d4ecc97b09f71e32edf Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Fri, 14 Oct 2022 07:51:30 +0200 Subject: [PATCH 005/102] Added auth service abc #70 --- src/bot_api/abc/auth_service_abc.py | 64 ++++++++++ src/bot_api/abc/select_criteria_abc.py | 17 +++ src/bot_api/filter/__init__.py | 0 .../filter/auth_user_select_criteria.py | 23 ++++ src/bot_api/model/auth_user_dto.py | 18 +++ src/bot_api/model/reset_password_dto.py | 18 +++ src/bot_api/model/settings_dto.py | 28 ++--- src/bot_api/model/token_dto.py | 18 +++ src/bot_api/model/update_auth_user_dto.py | 18 +++ src/bot_api/service/__init__.py | 1 + src/bot_api/service/auth_service.py | 4 + src/bot_data/migration/api_migration.py | 38 ++++++ src/bot_data/model/auth_role_enum.py | 7 ++ src/bot_data/model/auth_user.py | 109 ++++++++++++++++++ 14 files changed, 347 insertions(+), 16 deletions(-) create mode 100644 src/bot_api/abc/auth_service_abc.py create mode 100644 src/bot_api/abc/select_criteria_abc.py create mode 100644 src/bot_api/filter/__init__.py create mode 100644 src/bot_api/filter/auth_user_select_criteria.py create mode 100644 src/bot_api/model/auth_user_dto.py create mode 100644 src/bot_api/model/reset_password_dto.py create mode 100644 src/bot_api/model/token_dto.py create mode 100644 src/bot_api/model/update_auth_user_dto.py create mode 100644 src/bot_api/service/__init__.py create mode 100644 src/bot_api/service/auth_service.py create mode 100644 src/bot_data/migration/api_migration.py create mode 100644 src/bot_data/model/auth_role_enum.py create mode 100644 src/bot_data/model/auth_user.py diff --git a/src/bot_api/abc/auth_service_abc.py b/src/bot_api/abc/auth_service_abc.py new file mode 100644 index 0000000000..0141103e4e --- /dev/null +++ b/src/bot_api/abc/auth_service_abc.py @@ -0,0 +1,64 @@ +from abc import ABC, abstractmethod + +from cpl_query.extension import List + +from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria +from bot_api.model.auth_user_dto import AuthUserDTO +from bot_api.model.reset_password_dto import ResetPasswordDTO +from bot_api.model.token_dto import TokenDTO +from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO +from bot_data.model.auth_user import AuthUser + + +class AuthABC(ABC): + + @abstractmethod + def __init__(self): pass + + @abstractmethod + async def get_all_auth_users_async(self) -> List[AuthUser]: pass + + @abstractmethod + async def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> List[AuthUser]: pass + + @abstractmethod + async def get_auth_user_by_email_async(self, email: str) -> AuthUser: pass + + @abstractmethod + async def find_auth_user_by_email_async(self, email: str) -> AuthUser: pass + + @abstractmethod + async def add_auth_user_async(self, user_dto: AuthUserDTO) -> AuthUser: pass + + @abstractmethod + async def confirm_email_async(self, id: str) -> AuthUser: pass + + @abstractmethod + async def login_async(self, user_dto: AuthUserDTO) -> AuthUser: pass + + @abstractmethod + async def forgot_password_async(self, email: str) -> AuthUser: pass + + @abstractmethod + async def confirm_forgot_password_async(self, id: str) -> AuthUser: pass + + @abstractmethod + async def reset_password_async(self, rp_dto: ResetPasswordDTO) -> AuthUser: pass + + @abstractmethod + async def update_user_async(self, update_user_dto: UpdateAuthUserDTO) -> AuthUser: pass + + @abstractmethod + async def update_user_as_admin_async(self, update_user_dto: UpdateAuthUserDTO) -> AuthUser: pass + + @abstractmethod + async def refresh_async(self, token_dto: TokenDTO) -> AuthUser: pass + + @abstractmethod + async def revoke_async(self, token_dto: TokenDTO) -> AuthUser: pass + + @abstractmethod + async def delete_auth_user_by_email_async(self, email: str) -> AuthUser: pass + + @abstractmethod + async def delete_auth_user_async(self, user_dto: AuthUserDTO) -> AuthUser: pass diff --git a/src/bot_api/abc/select_criteria_abc.py b/src/bot_api/abc/select_criteria_abc.py new file mode 100644 index 0000000000..234f7865b3 --- /dev/null +++ b/src/bot_api/abc/select_criteria_abc.py @@ -0,0 +1,17 @@ +from abc import ABC, abstractmethod + + +class SelectCriteriaABC(ABC): + + @abstractmethod + def __init__( + self, + page_index: int, + page_size: int, + sort_direction: str, + sort_column: str + ): + self.page_index = page_index + self.page_size = page_size + self.sort_direction = sort_direction + self.sort_column = sort_column diff --git a/src/bot_api/filter/__init__.py b/src/bot_api/filter/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/bot_api/filter/auth_user_select_criteria.py b/src/bot_api/filter/auth_user_select_criteria.py new file mode 100644 index 0000000000..497f5eaa18 --- /dev/null +++ b/src/bot_api/filter/auth_user_select_criteria.py @@ -0,0 +1,23 @@ +from bot_api.abc.select_criteria_abc import SelectCriteriaABC + + +class AuthUserSelectCriteria(SelectCriteriaABC): + + def __init__( + self, + page_index: int, + page_size: int, + sort_direction: str, + sort_column: str, + + first_name: str, + last_name: str, + email: str, + auth_role=0 + ): + SelectCriteriaABC.__init__(self, page_index, page_size, sort_direction, sort_column) + + self.first_name = first_name + self.last_name = last_name + self.email = email + self.auth_role = auth_role diff --git a/src/bot_api/model/auth_user_dto.py b/src/bot_api/model/auth_user_dto.py new file mode 100644 index 0000000000..f43dde4e0e --- /dev/null +++ b/src/bot_api/model/auth_user_dto.py @@ -0,0 +1,18 @@ +import traceback + +from cpl_core.console import Console + +from bot_api.abc.dto_abc import DtoABC + + +class AuthUserDTO(DtoABC): + + def __init__(self): + DtoABC.__init__(self) + + def from_dict(self, values: dict): + pass + + def to_dict(self) -> dict: + return { + } diff --git a/src/bot_api/model/reset_password_dto.py b/src/bot_api/model/reset_password_dto.py new file mode 100644 index 0000000000..240437cdfa --- /dev/null +++ b/src/bot_api/model/reset_password_dto.py @@ -0,0 +1,18 @@ +import traceback + +from cpl_core.console import Console + +from bot_api.abc.dto_abc import DtoABC + + +class ResetPasswordDTO(DtoABC): + + def __init__(self): + DtoABC.__init__(self) + + def from_dict(self, values: dict): + pass + + def to_dict(self) -> dict: + return { + } diff --git a/src/bot_api/model/settings_dto.py b/src/bot_api/model/settings_dto.py index 6d72245ba2..ce3ec436cc 100644 --- a/src/bot_api/model/settings_dto.py +++ b/src/bot_api/model/settings_dto.py @@ -1,7 +1,3 @@ -import traceback - -from cpl_core.console import Console - from bot_api.abc.dto_abc import DtoABC from bot_api.model.version_dto import VersionDTO @@ -25,20 +21,20 @@ class SettingsDTO(DtoABC): ): DtoABC.__init__(self) - self._web_version = '' - self._api_version = VersionDTO() - self._config_path = '' - self._web_base_url = '' - self._api_base_url = '' + self._web_version = web_version + self._api_version = api_version + self._config_path = config_path + self._web_base_url = web_base_url + self._api_base_url = api_base_url - self._token_expire_time = 0 - self._refresh_token_expire_time = 0 + self._token_expire_time = token_expire_time + self._refresh_token_expire_time = refresh_token_expire_time - self._mail_user = '' - self._mail_port = 0 - self._mail_host = '' - self._mail_transceiver = '' - self._mail_transceiver_address = '' + self._mail_user = mail_user + self._mail_port = mail_port + self._mail_host = mail_host + self._mail_transceiver = mail_transceiver + self._mail_transceiver_address = mail_transceiver_address def from_dict(self, values: dict): self._web_version = values['WebVersion'] diff --git a/src/bot_api/model/token_dto.py b/src/bot_api/model/token_dto.py new file mode 100644 index 0000000000..445943c248 --- /dev/null +++ b/src/bot_api/model/token_dto.py @@ -0,0 +1,18 @@ +import traceback + +from cpl_core.console import Console + +from bot_api.abc.dto_abc import DtoABC + + +class TokenDTO(DtoABC): + + def __init__(self): + DtoABC.__init__(self) + + def from_dict(self, values: dict): + pass + + def to_dict(self) -> dict: + return { + } diff --git a/src/bot_api/model/update_auth_user_dto.py b/src/bot_api/model/update_auth_user_dto.py new file mode 100644 index 0000000000..b7d501f587 --- /dev/null +++ b/src/bot_api/model/update_auth_user_dto.py @@ -0,0 +1,18 @@ +import traceback + +from cpl_core.console import Console + +from bot_api.abc.dto_abc import DtoABC + + +class UpdateAuthUserDTO(DtoABC): + + def __init__(self): + DtoABC.__init__(self) + + def from_dict(self, values: dict): + pass + + def to_dict(self) -> dict: + return { + } diff --git a/src/bot_api/service/__init__.py b/src/bot_api/service/__init__.py new file mode 100644 index 0000000000..425ab6c146 --- /dev/null +++ b/src/bot_api/service/__init__.py @@ -0,0 +1 @@ +# imports diff --git a/src/bot_api/service/auth_service.py b/src/bot_api/service/auth_service.py new file mode 100644 index 0000000000..cc9ecbbd75 --- /dev/null +++ b/src/bot_api/service/auth_service.py @@ -0,0 +1,4 @@ +class AuthService: + + def __init__(self): + pass diff --git a/src/bot_data/migration/api_migration.py b/src/bot_data/migration/api_migration.py new file mode 100644 index 0000000000..187dc5fcbe --- /dev/null +++ b/src/bot_data/migration/api_migration.py @@ -0,0 +1,38 @@ +from bot_core.logging.database_logger import DatabaseLogger +from bot_data.abc.migration_abc import MigrationABC +from bot_data.db_context import DBContext + + +class ApiMigration(MigrationABC): + name = '0.3_ApiMigration' + + def __init__(self, logger: DatabaseLogger, db: DBContext): + MigrationABC.__init__(self) + self._logger = logger + self._db = db + self._cursor = db.cursor + + def upgrade(self): + self._logger.debug(__name__, 'Running upgrade') + + self._cursor.execute( + str(f""" + CREATE TABLE IF NOT EXISTS `AuthUsers` ( + `Id` bigint NOT NULL, + `FirstName` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, + `LastName` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, + `EMail` varchar(255) DEFAULT NULL, + `Password` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, + `RefreshToken` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, + `ConfirmationId` varchar(255) DEFAULT NULL, + `ForgotPasswordId` varchar(255) DEFAULT NULL, + `RefreshTokenExpiryTime` datetime(6) NOT NULL, + `AuthRole` int NOT NULL DEFAULT '0' + `CreatedOn` datetime(6) NOT NULL, + `LastModifiedOn` datetime(6) NOT NULL, + ) + """) + ) + + def downgrade(self): + self._cursor.execute('DROP TABLE `AuthUsers`;') diff --git a/src/bot_data/model/auth_role_enum.py b/src/bot_data/model/auth_role_enum.py new file mode 100644 index 0000000000..8b03232577 --- /dev/null +++ b/src/bot_data/model/auth_role_enum.py @@ -0,0 +1,7 @@ +from enum import Enum + + +class AuthRoleEnum(Enum): + + Normal = 0 + Admin = 1 diff --git a/src/bot_data/model/auth_user.py b/src/bot_data/model/auth_user.py new file mode 100644 index 0000000000..37b50d99c9 --- /dev/null +++ b/src/bot_data/model/auth_user.py @@ -0,0 +1,109 @@ +from datetime import datetime +from typing import Optional +from cpl_core.database import TableABC + +from bot_data.model.auth_role_enum import AuthRoleEnum +from bot_data.model.server import Server + + +class AuthUser(TableABC): + + def __init__( + self, + first_name: str, + last_name: str, + email: str, + password: str, + refresh_token: str, + confirmation_id: str, + forgot_password_id: str, + refresh_token_expire_time: datetime, + auth_role: AuthRoleEnum, + created_at: datetime = None, + modified_at: datetime = None, + id=0 + ): + self._auth_user_id = id + self._first_name = first_name + self._last_name = last_name + self._email = email + self._password = password + self._refresh_token = refresh_token + self._confirmation_id = confirmation_id + self._forgot_password_id = forgot_password_id + self._refresh_token_expire_time = refresh_token_expire_time + + self._auth_role_id = auth_role.value + + TableABC.__init__(self) + self._created_at = created_at if created_at is not None else self._created_at + self._modified_at = modified_at if modified_at is not None else self._modified_at + + @staticmethod + def get_select_all_string() -> str: + return str(f""" + SELECT * FROM `AuthUsers`; + """) + + @staticmethod + def get_select_by_id_string(id: int) -> str: + return str(f""" + SELECT * FROM `AuthUsers` + WHERE `Id` = {id}; + """) + + @property + def insert_string(self) -> str: + return str(f""" + INSERT INTO `AuthUsers` ( + `Id`, + `FirstName`, + `LastName`, + `EMail`, + `Password`, + `RefreshToken`, + `ConfirmationId`, + `ForgotPasswordId`, + `RefreshTokenExpiryTime`, + `AuthRole`, + `CreatedOn`, + `LastModifiedOn` + ) VALUES ( + {self._auth_user_id}, + {self._first_name}, + {self._last_name}, + {self._email}, + {self._password}, + {self._refresh_token}, + {self._confirmation_id}, + {self._forgot_password_id}, + {self._refresh_token_expire_time}, + {self._auth_role_id} + {self._created_at}, + {self._modified_at} + ) + """) + + @property + def udpate_string(self) -> str: + return str(f""" + UPDATE `AuthUsers` + SET `FirstName` = '{self._first_name}', + `LastName` = '{self._last_name}', + `EMail` = '{self._email}', + `Password` = '{self._password}', + `RefreshToken` = '{self._refresh_token}', + `ConfirmationId` = '{self._confirmation_id}', + `ForgotPasswordId` = '{self._forgot_password_id}', + `RefreshTokenExpiryTime` = '{self._refresh_token_expire_time}', + `AutoRole` = {self._auth_role_id}, + `LastModifiedAt` = '{self._modified_at}' + WHERE `AuthUsers`.`Id` = {self._auth_user_id}; + """) + + @property + def delete_string(self) -> str: + return str(f""" + DELETE FROM `AuthUsers` + WHERE `Id` = {self._auth_user_id}; + """) From 411e44a6812086a27e4fad3e634cc138c249857d Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Fri, 14 Oct 2022 10:35:58 +0200 Subject: [PATCH 006/102] [WIP] Added auth controller & updated pakages #70 --- src/bot_api/api.py | 18 ++++++--- src/bot_api/api_module.py | 2 + src/bot_api/bot-api.json | 7 +++- src/bot_api/configuration/__init__.py | 25 ++++++++++++ src/bot_api/controller/auth_controller.py | 47 +++++++++++++++++++++++ src/bot_api/filter/__init__.py | 26 +++++++++++++ src/bot_api/route/route.py | 4 +- src/bot_api/service/__init__.py | 25 ++++++++++++ src/bot_core/bot-core.json | 2 +- src/bot_data/bot-data.json | 2 +- src/modules/admin/admin.json | 2 +- src/modules/auto_role/auto-role.json | 2 +- src/modules/base/base.json | 2 +- src/modules/boot_log/boot-log.json | 2 +- src/modules/database/database.json | 2 +- src/modules/moderator/moderator.json | 2 +- src/modules/permission/permission.json | 2 +- 17 files changed, 154 insertions(+), 18 deletions(-) create mode 100644 src/bot_api/controller/auth_controller.py diff --git a/src/bot_api/api.py b/src/bot_api/api.py index c404350521..29c176fa5e 100644 --- a/src/bot_api/api.py +++ b/src/bot_api/api.py @@ -1,8 +1,10 @@ import sys from functools import partial +from blinker import Namespace from cpl_core.dependency_injection import ServiceProviderABC from flask import Flask, request +from flask_cors import CORS from bot_api.configuration.api_settings import ApiSettings from bot_api.logging.api_logger import ApiLogger @@ -27,20 +29,26 @@ class Api(Flask): self._services = services self._apt_settings = api_settings + self._cors = CORS(self, support_credentials=True) + # register before request self.before_request_funcs.setdefault(None, []).append(self.before_request) + my_signals = Namespace() + notify = my_signals.signal('notify') def _register_routes(self): for path, f in Route.registered_routes.items(): + route = f[0] + kwargs = f[1] cls = None - qual_name_split = f.__qualname__.split('.') + qual_name_split = route.__qualname__.split('.') if len(qual_name_split) > 0: - cls_type = vars(sys.modules[f.__module__])[qual_name_split[0]] + cls_type = vars(sys.modules[route.__module__])[qual_name_split[0]] cls = self._services.get_service(cls_type) - partial_f = partial(f, self if cls is None else cls) - partial_f.__name__ = f.__name__ - self.route(path)(partial_f) + partial_f = partial(route, self if cls is None else cls) + partial_f.__name__ = route.__name__ + self.route(path, **kwargs)(partial_f) def before_request(self, *args, **kwargs): self._logger.debug(__name__, f'Received GET @{request.url}') diff --git a/src/bot_api/api_module.py b/src/bot_api/api_module.py index 3f26d80c56..be126e6550 100644 --- a/src/bot_api/api_module.py +++ b/src/bot_api/api_module.py @@ -10,6 +10,7 @@ from flask import Flask from bot_api.api import Api from bot_api.api_thread import ApiThread from bot_api.controller.api_controller import ApiController +from bot_api.controller.auth_controller import AuthController from bot_core.abc.module_abc import ModuleABC from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum @@ -33,4 +34,5 @@ class ApiModule(ModuleABC): services.add_singleton(ApiThread) services.add_singleton(Flask, Api) + services.add_transient(AuthController) services.add_transient(ApiController) diff --git a/src/bot_api/bot-api.json b/src/bot_api/bot-api.json index 09e4129308..7b66f8efe5 100644 --- a/src/bot_api/bot-api.json +++ b/src/bot_api/bot-api.json @@ -17,11 +17,14 @@ "LicenseDescription": "", "Dependencies": [ "cpl-core==2022.10.0.post6", + "Flask==2.2.2", "Flask[async]==2.2.2", - "Flask-Classful==0.14.2" + "Flask-Classful==0.14.2", + "Flask-Cors==3.0.10", + "PyJWT==2.5.0" ], "DevDependencies": [ - "cpl-cli>=2022.10.0" + "cpl-cli==2022.10.0" ], "PythonVersion": ">=3.10.4", "PythonPath": { diff --git a/src/bot_api/configuration/__init__.py b/src/bot_api/configuration/__init__.py index 425ab6c146..86e07283fa 100644 --- a/src/bot_api/configuration/__init__.py +++ b/src/bot_api/configuration/__init__.py @@ -1 +1,26 @@ +# -*- coding: utf-8 -*- + +""" +bot Keksdose bot +~~~~~~~~~~~~~~~~~~~ + +Discord bot for the Keksdose discord Server + +:copyright: (c) 2022 sh-edraft.de +:license: MIT, see LICENSE for more details. + +""" + +__title__ = 'bot_api.configuration' +__author__ = 'Sven Heidemann' +__license__ = 'MIT' +__copyright__ = 'Copyright (c) 2022 sh-edraft.de' +__version__ = '0.2.3' + +from collections import namedtuple + + # imports + +VersionInfo = namedtuple('VersionInfo', 'major minor micro') +version_info = VersionInfo(major='0', minor='2', micro='3') diff --git a/src/bot_api/controller/auth_controller.py b/src/bot_api/controller/auth_controller.py new file mode 100644 index 0000000000..40427bdab5 --- /dev/null +++ b/src/bot_api/controller/auth_controller.py @@ -0,0 +1,47 @@ +from cpl_core.configuration import ConfigurationABC +from cpl_core.environment import ApplicationEnvironmentABC +from cpl_core.mailing import EMailClientABC, EMailClientSettings +from cpl_query.extension import List +from cpl_translation import TranslatePipe +from flask import request +from flask_cors import cross_origin + +from bot_api.api import Api +from bot_api.logging.api_logger import ApiLogger +from bot_api.model.token_dto import TokenDTO +from bot_api.route.route import Route +from bot_data.model.auth_user import AuthUser + + +class AuthController: + + def __init__( + self, + config: ConfigurationABC, + env: ApplicationEnvironmentABC, + logger: ApiLogger, + t: TranslatePipe, + api: Api, + mail_settings: EMailClientSettings, + mailer: EMailClientABC + ): + self._config = config + self._env = env + self._logger = logger + self._t = t + self._api = api + self._mail_settings = mail_settings + self._mailer = mailer + + @Route.route('/api/auth/get-all-users') + async def get_all_users(self) -> List[AuthUser]: + pass + + @Route.route('/api/auth/get-filtered-users', methods=['POST']) + async def get_filtered_users(self) -> List[AuthUser]: + pass + + @Route.route('/api/auth/login', methods=['POST']) + async def login(self) -> dict: + self._logger.warn(__name__, f'Received {request.json}') + return TokenDTO().to_dict() diff --git a/src/bot_api/filter/__init__.py b/src/bot_api/filter/__init__.py index e69de29bb2..0f9e52aa6a 100644 --- a/src/bot_api/filter/__init__.py +++ b/src/bot_api/filter/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +""" +bot Keksdose bot +~~~~~~~~~~~~~~~~~~~ + +Discord bot for the Keksdose discord Server + +:copyright: (c) 2022 sh-edraft.de +:license: MIT, see LICENSE for more details. + +""" + +__title__ = 'bot_api.filter' +__author__ = 'Sven Heidemann' +__license__ = 'MIT' +__copyright__ = 'Copyright (c) 2022 sh-edraft.de' +__version__ = '0.2.3' + +from collections import namedtuple + + +# imports: + +VersionInfo = namedtuple('VersionInfo', 'major minor micro') +version_info = VersionInfo(major='0', minor='2', micro='3') diff --git a/src/bot_api/route/route.py b/src/bot_api/route/route.py index ef0e399403..9dbe7fcbfa 100644 --- a/src/bot_api/route/route.py +++ b/src/bot_api/route/route.py @@ -2,10 +2,10 @@ class Route: registered_routes = {} @classmethod - def route(cls, path=None): + def route(cls, path=None, **kwargs): # simple decorator for class based views def inner(fn): - cls.registered_routes[path] = fn + cls.registered_routes[path] = (fn, kwargs) return fn return inner diff --git a/src/bot_api/service/__init__.py b/src/bot_api/service/__init__.py index 425ab6c146..3a5cf24d73 100644 --- a/src/bot_api/service/__init__.py +++ b/src/bot_api/service/__init__.py @@ -1 +1,26 @@ +# -*- coding: utf-8 -*- + +""" +bot Keksdose bot +~~~~~~~~~~~~~~~~~~~ + +Discord bot for the Keksdose discord Server + +:copyright: (c) 2022 sh-edraft.de +:license: MIT, see LICENSE for more details. + +""" + +__title__ = 'bot_api.service' +__author__ = 'Sven Heidemann' +__license__ = 'MIT' +__copyright__ = 'Copyright (c) 2022 sh-edraft.de' +__version__ = '0.2.3' + +from collections import namedtuple + + # imports + +VersionInfo = namedtuple('VersionInfo', 'major minor micro') +version_info = VersionInfo(major='0', minor='2', micro='3') diff --git a/src/bot_core/bot-core.json b/src/bot_core/bot-core.json index 6720bf0f2e..502ce6c618 100644 --- a/src/bot_core/bot-core.json +++ b/src/bot_core/bot-core.json @@ -19,7 +19,7 @@ "cpl-core>=2022.10.0" ], "DevDependencies": [ - "cpl-cli>=2022.10.0" + "cpl-cli==2022.10.0" ], "PythonVersion": ">=3.10.4", "PythonPath": { diff --git a/src/bot_data/bot-data.json b/src/bot_data/bot-data.json index e92af7de3c..99af9f44e4 100644 --- a/src/bot_data/bot-data.json +++ b/src/bot_data/bot-data.json @@ -19,7 +19,7 @@ "cpl-core>=2022.10.0" ], "DevDependencies": [ - "cpl-cli>=2022.10.0" + "cpl-cli==2022.10.0" ], "PythonVersion": ">=3.10.4", "PythonPath": { diff --git a/src/modules/admin/admin.json b/src/modules/admin/admin.json index 446e16f30a..e76e9180f8 100644 --- a/src/modules/admin/admin.json +++ b/src/modules/admin/admin.json @@ -19,7 +19,7 @@ "cpl-core>=2022.10.0.post5" ], "DevDependencies": [ - "cpl-cli>=2022.10.0" + "cpl-cli==2022.10.0" ], "PythonVersion": ">=3.10.4", "PythonPath": { diff --git a/src/modules/auto_role/auto-role.json b/src/modules/auto_role/auto-role.json index 8e29094ce9..f87561551d 100644 --- a/src/modules/auto_role/auto-role.json +++ b/src/modules/auto_role/auto-role.json @@ -19,7 +19,7 @@ "cpl-core>=2022.10.0.post5" ], "DevDependencies": [ - "cpl-cli>=2022.10.0" + "cpl-cli==2022.10.0" ], "PythonVersion": ">=3.10.4", "PythonPath": { diff --git a/src/modules/base/base.json b/src/modules/base/base.json index 4371622ce5..a77d7c5b60 100644 --- a/src/modules/base/base.json +++ b/src/modules/base/base.json @@ -19,7 +19,7 @@ "cpl-core>=2022.10.0.post2" ], "DevDependencies": [ - "cpl-cli>=2022.10.0" + "cpl-cli==2022.10.0" ], "PythonVersion": ">=3.10.4", "PythonPath": { diff --git a/src/modules/boot_log/boot-log.json b/src/modules/boot_log/boot-log.json index bf1e0b5b1e..0090d83c50 100644 --- a/src/modules/boot_log/boot-log.json +++ b/src/modules/boot_log/boot-log.json @@ -19,7 +19,7 @@ "cpl-core>=2022.10.0.post2" ], "DevDependencies": [ - "cpl-cli>=2022.10.0" + "cpl-cli==2022.10.0" ], "PythonVersion": ">=3.10.4", "PythonPath": { diff --git a/src/modules/database/database.json b/src/modules/database/database.json index efcaea3f3e..c4b05683cf 100644 --- a/src/modules/database/database.json +++ b/src/modules/database/database.json @@ -19,7 +19,7 @@ "cpl-core>=2022.10.0.post2" ], "DevDependencies": [ - "cpl-cli>=2022.10.0" + "cpl-cli==2022.10.0" ], "PythonVersion": ">=3.10.4", "PythonPath": { diff --git a/src/modules/moderator/moderator.json b/src/modules/moderator/moderator.json index 45dca24c5b..034735a69b 100644 --- a/src/modules/moderator/moderator.json +++ b/src/modules/moderator/moderator.json @@ -19,7 +19,7 @@ "cpl-core>=2022.10.0.post5" ], "DevDependencies": [ - "cpl-cli>=2022.10.0" + "cpl-cli==2022.10.0" ], "PythonVersion": ">=3.10.4", "PythonPath": { diff --git a/src/modules/permission/permission.json b/src/modules/permission/permission.json index f5c9608797..86cbc3c749 100644 --- a/src/modules/permission/permission.json +++ b/src/modules/permission/permission.json @@ -19,7 +19,7 @@ "cpl-core>=2022.10.0.post2" ], "DevDependencies": [ - "cpl-cli>=2022.10.0" + "cpl-cli==2022.10.0" ], "PythonVersion": ">=3.10.4", "PythonPath": { From 2457107c63d0110f24e2ce44a4ddb48f4c1255cc Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Fri, 14 Oct 2022 13:05:53 +0200 Subject: [PATCH 007/102] Added auth user repository #70 --- src/bot_data/abc/auth_user_repository_abc.py | 41 ++++++ src/bot_data/data_module.py | 3 + src/bot_data/filtered_result.py | 24 ++++ src/bot_data/model/auth_user.py | 59 ++++++++- .../service/auth_user_repository_service.py | 125 ++++++++++++++++++ 5 files changed, 249 insertions(+), 3 deletions(-) create mode 100644 src/bot_data/abc/auth_user_repository_abc.py create mode 100644 src/bot_data/filtered_result.py create mode 100644 src/bot_data/service/auth_user_repository_service.py diff --git a/src/bot_data/abc/auth_user_repository_abc.py b/src/bot_data/abc/auth_user_repository_abc.py new file mode 100644 index 0000000000..161187461e --- /dev/null +++ b/src/bot_data/abc/auth_user_repository_abc.py @@ -0,0 +1,41 @@ +from abc import ABC, abstractmethod +from typing import Optional + +from cpl_query.extension import List + +from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria +from bot_data.filtered_result import FilteredResult +from bot_data.model.auth_user import AuthUser + + +class AuthUserRepositoryABC(ABC): + + @abstractmethod + def __init__(self): pass + + @abstractmethod + def get_all_auth_users(self) -> List[AuthUser]: pass + + @abstractmethod + def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> FilteredResult: pass + + @abstractmethod + def get_auth_user_by_email_async(self, email: str) -> AuthUser: pass + + @abstractmethod + def find_auth_user_by_email_async(self, email: str) -> Optional[AuthUser]: pass + + @abstractmethod + def find_auth_user_by_confirmation_id_async(self, id: str) -> Optional[AuthUser]: pass + + @abstractmethod + def find_auth_user_by_forgot_password_id_async(self, id: str) -> Optional[AuthUser]: pass + + @abstractmethod + def add_auth_user(self, user: AuthUser): pass + + @abstractmethod + def update_auth_user(self, user: AuthUser): pass + + @abstractmethod + def delete_auth_user(self, user: AuthUser): pass diff --git a/src/bot_data/data_module.py b/src/bot_data/data_module.py index 99fc12ad0d..7537b6f282 100644 --- a/src/bot_data/data_module.py +++ b/src/bot_data/data_module.py @@ -5,6 +5,7 @@ from cpl_discord.service.discord_collection_abc import DiscordCollectionABC from bot_core.abc.module_abc import ModuleABC from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum +from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC from bot_data.abc.auto_role_repository_abc import AutoRoleRepositoryABC from bot_data.abc.client_repository_abc import ClientRepositoryABC from bot_data.abc.known_user_repository_abc import KnownUserRepositoryABC @@ -12,6 +13,7 @@ from bot_data.abc.server_repository_abc import ServerRepositoryABC from bot_data.abc.user_joined_server_repository_abc import UserJoinedServerRepositoryABC from bot_data.abc.user_joined_voice_channel_abc import UserJoinedVoiceChannelRepositoryABC from bot_data.abc.user_repository_abc import UserRepositoryABC +from bot_data.service.auth_user_repository_service import AuthUserRepositoryService from bot_data.service.auto_role_repository_service import AutoRoleRepositoryService from bot_data.service.client_repository_service import ClientRepositoryService from bot_data.service.known_user_repository_service import KnownUserRepositoryService @@ -30,6 +32,7 @@ class DataModule(ModuleABC): pass def configure_services(self, services: ServiceCollectionABC, env: ApplicationEnvironmentABC): + services.add_transient(AuthUserRepositoryABC, AuthUserRepositoryService) services.add_transient(ServerRepositoryABC, ServerRepositoryService) services.add_transient(UserRepositoryABC, UserRepositoryService) services.add_transient(ClientRepositoryABC, ClientRepositoryService) diff --git a/src/bot_data/filtered_result.py b/src/bot_data/filtered_result.py new file mode 100644 index 0000000000..8bdf90a314 --- /dev/null +++ b/src/bot_data/filtered_result.py @@ -0,0 +1,24 @@ +from cpl_query.extension import List + + +class FilteredResult: + + def __init__(self, result: List = None, total_count: int = 0): + self._result = [] if result is None else result + self._total_count = total_count + + @property + def result(self) -> List: + return self._result + + @result.setter + def result(self, value: List): + self._result = value + + @property + def total_count(self) -> int: + return self._total_count + + @total_count.setter + def total_count(self, value: int): + self._total_count = value diff --git a/src/bot_data/model/auth_user.py b/src/bot_data/model/auth_user.py index 37b50d99c9..6078f2099b 100644 --- a/src/bot_data/model/auth_user.py +++ b/src/bot_data/model/auth_user.py @@ -33,12 +33,44 @@ class AuthUser(TableABC): self._forgot_password_id = forgot_password_id self._refresh_token_expire_time = refresh_token_expire_time - self._auth_role_id = auth_role.value + self._auth_role_id = auth_role TableABC.__init__(self) self._created_at = created_at if created_at is not None else self._created_at self._modified_at = modified_at if modified_at is not None else self._modified_at + @property + def id(self) -> int: + return self._auth_user_id + + @property + def first_name(self) -> str: + return self._first_name + + @property + def last_name(self) -> str: + return self._last_name + + @property + def email(self) -> str: + return self._email + + @property + def password(self) -> str: + return self._password + + @property + def refresh_token(self) -> str: + return self._refresh_token + + @property + def refresh_token_expire_time(self) -> datetime: + return self._refresh_token_expire_time + + @property + def auth_role(self) -> AuthRoleEnum: + return self._auth_role_id + @staticmethod def get_select_all_string() -> str: return str(f""" @@ -52,6 +84,27 @@ class AuthUser(TableABC): WHERE `Id` = {id}; """) + @staticmethod + def get_select_by_email_string(email: str) -> str: + return str(f""" + SELECT * FROM `AuthUsers` + WHERE `EMail` = {email}; + """) + + @staticmethod + def get_select_by_confirmation_id_string(id: str) -> str: + return str(f""" + SELECT * FROM `AuthUsers` + WHERE `ConfirmationId` = {id}; + """) + + @staticmethod + def get_select_by_forgot_password_i_string(id: str) -> str: + return str(f""" + SELECT * FROM `AuthUsers` + WHERE `ForgotPasswordId` = {id}; + """) + @property def insert_string(self) -> str: return str(f""" @@ -78,7 +131,7 @@ class AuthUser(TableABC): {self._confirmation_id}, {self._forgot_password_id}, {self._refresh_token_expire_time}, - {self._auth_role_id} + {self._auth_role_id.value} {self._created_at}, {self._modified_at} ) @@ -96,7 +149,7 @@ class AuthUser(TableABC): `ConfirmationId` = '{self._confirmation_id}', `ForgotPasswordId` = '{self._forgot_password_id}', `RefreshTokenExpiryTime` = '{self._refresh_token_expire_time}', - `AutoRole` = {self._auth_role_id}, + `AutoRole` = {self._auth_role_id.value}, `LastModifiedAt` = '{self._modified_at}' WHERE `AuthUsers`.`Id` = {self._auth_user_id}; """) diff --git a/src/bot_data/service/auth_user_repository_service.py b/src/bot_data/service/auth_user_repository_service.py new file mode 100644 index 0000000000..aca3e94af2 --- /dev/null +++ b/src/bot_data/service/auth_user_repository_service.py @@ -0,0 +1,125 @@ +from typing import Optional + +from cpl_core.database.context import DatabaseContextABC +from cpl_query.extension import List + +from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria +from bot_core.logging.database_logger import DatabaseLogger +from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC +from bot_data.filtered_result import FilteredResult +from bot_data.model.auth_role_enum import AuthRoleEnum +from bot_data.model.auth_user import AuthUser + + +class AuthUserRepositoryService(AuthUserRepositoryABC): + + def __init__(self, logger: DatabaseLogger, db_context: DatabaseContextABC): + self._logger = logger + self._context = db_context + + AuthUserRepositoryABC.__init__(self) + + @staticmethod + def _user_from_result(result: tuple) -> AuthUser: + return AuthUser( + result[1], + result[2], + result[3], + result[4], + result[5], + result[6], + result[7], + result[8], + AuthRoleEnum(result[9]), + id=result[0] + ) + + def get_all_auth_users(self) -> List[AuthUser]: + users = List(AuthUser) + self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_all_string()}') + results = self._context.select(AuthUser.get_select_all_string()) + for result in results: + self._logger.trace(__name__, f'Get auth user with id {result[0]}') + users.append(self._user_from_result(result)) + + return users + + def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> FilteredResult: + users = self.get_all_auth_users() + self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_all_string()}') + + query = users + + if criteria.first_name is not None and criteria.first_name != '': + query = query.where(lambda x: criteria.first_name in x.first_name or x.first_name == criteria.first_name) + + if criteria.last_name is not None and criteria.last_name != '': + query = query.where(lambda x: criteria.last_name in x.last_name or x.last_name == criteria.last_name) + + if criteria.email is not None and criteria.email != '': + query = query.where(lambda x: criteria.email in x.email or x.email == criteria.email) + + if criteria.auth_role is not None: + query = query.where(lambda x: x.auth_role == AuthRoleEnum(criteria.auth_role)) + + # sort + if criteria.sort_column is not None and criteria.sort_column != '' and criteria.sort_direction is not None and criteria.sort_direction: + crit_sort_direction = criteria.sort_direction.lower() + if crit_sort_direction == "desc" or crit_sort_direction == "descending": + query = query.order_by_descending(lambda x: getattr(x, criteria.sort_column)) + else: + query = query.order_by(lambda x: getattr(x, criteria.sort_column)) + + skip = criteria.page_size * criteria.page_index + result = FilteredResult() + result.total_count = query.count() + result.result = query.skip(skip).take(criteria.page_size) + + return result + + def get_auth_user_by_email_async(self, email: str) -> AuthUser: + self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_by_email_string(email)}') + result = self._context.select(AuthUser.get_select_by_email_string(email))[0] + return self._user_from_result(result) + + def find_auth_user_by_email_async(self, email: str) -> Optional[AuthUser]: + self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_by_email_string(email)}') + result = self._context.select(AuthUser.get_select_by_email_string(email)) + if result is None or len(result) == 0: + return None + + result = result[0] + + return self._user_from_result(result) + + def find_auth_user_by_confirmation_id_async(self, id: str) -> Optional[AuthUser]: + self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_by_email_string(id)}') + result = self._context.select(AuthUser.get_select_by_email_string(id)) + if result is None or len(result) == 0: + return None + + result = result[0] + + return self._user_from_result(result) + + def find_auth_user_by_forgot_password_id_async(self, id: str) -> Optional[AuthUser]: + self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_by_email_string(id)}') + result = self._context.select(AuthUser.get_select_by_email_string(id)) + if result is None or len(result) == 0: + return None + + result = result[0] + + return self._user_from_result(result) + + def add_auth_user(self, user: AuthUser): + self._logger.trace(__name__, f'Send SQL command: {user.insert_string}') + self._context.cursor.execute(user.insert_string) + + def update_auth_user(self, user: AuthUser): + self._logger.trace(__name__, f'Send SQL command: {user.udpate_string}') + self._context.cursor.execute(user.udpate_string) + + def delete_auth_user(self, user: AuthUser): + self._logger.trace(__name__, f'Send SQL command: {user.delete_string}') + self._context.cursor.execute(user.delete_string) From 126637306def102558fbcefa13ec5098f372b863 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Fri, 14 Oct 2022 13:17:25 +0200 Subject: [PATCH 008/102] [WIP] Added auth user service #70 --- src/bot_api/abc/auth_service_abc.py | 2 +- src/bot_api/model/auth_user_dto.py | 46 +++++++++++++++++++++- src/bot_api/service/auth_service.py | 61 ++++++++++++++++++++++++++++- 3 files changed, 105 insertions(+), 4 deletions(-) diff --git a/src/bot_api/abc/auth_service_abc.py b/src/bot_api/abc/auth_service_abc.py index 0141103e4e..c34af36997 100644 --- a/src/bot_api/abc/auth_service_abc.py +++ b/src/bot_api/abc/auth_service_abc.py @@ -10,7 +10,7 @@ from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO from bot_data.model.auth_user import AuthUser -class AuthABC(ABC): +class AuthServiceABC(ABC): @abstractmethod def __init__(self): pass diff --git a/src/bot_api/model/auth_user_dto.py b/src/bot_api/model/auth_user_dto.py index f43dde4e0e..7ca44a9e6c 100644 --- a/src/bot_api/model/auth_user_dto.py +++ b/src/bot_api/model/auth_user_dto.py @@ -1,18 +1,60 @@ import traceback +from typing import Optional from cpl_core.console import Console from bot_api.abc.dto_abc import DtoABC +from bot_data.model.auth_role_enum import AuthRoleEnum class AuthUserDTO(DtoABC): - def __init__(self): + def __init__( + self, + id: int, + first_name: str, + last_name: str, + email: str, + password: str, + confirmation_id: Optional[str], + auth_role: AuthRoleEnum, + ): DtoABC.__init__(self) + self._id = id + self._first_name = first_name + self._last_name = last_name + self._email = email + self._password = password + self._is_confirmed = confirmation_id is None + self._auth_role = auth_role + + """ + long Id { get; set; } + string FirstName { get; set; } + string LastName { get; set; } + string EMail { get; set; } + string Password { get; set; } + bool IsConfirmed { get; set; } + AuthRoles AuthRole { get; set; } + """ + def from_dict(self, values: dict): - pass + self._id = values['Id'] + self._first_name = values['FirstName'] + self._last_name = values['LastName'] + self._email = values['EMail'] + self._password = values['Password'] + self._is_confirmed = values['IsConfirmed'] + self._auth_role = values['AuthRole'] def to_dict(self) -> dict: return { + "Id": self._id, + "FirstName": self._first_name, + "LastName": self._last_name, + "EMail": self._email, + "Password": self._password, + "IsConfirmed": self._is_confirmed, + "AuthRole": self._auth_role, } diff --git a/src/bot_api/service/auth_service.py b/src/bot_api/service/auth_service.py index cc9ecbbd75..3455c08328 100644 --- a/src/bot_api/service/auth_service.py +++ b/src/bot_api/service/auth_service.py @@ -1,4 +1,63 @@ -class AuthService: +from cpl_query.extension import List + +from bot_api.abc.auth_service_abc import AuthServiceABC +from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria +from bot_api.model.auth_user_dto import AuthUserDTO +from bot_api.model.reset_password_dto import ResetPasswordDTO +from bot_api.model.token_dto import TokenDTO +from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO +from bot_data.model.auth_user import AuthUser + + +class AuthService(AuthServiceABC): def __init__(self): pass + + async def get_all_auth_users_async(self) -> List[AuthUser]: + pass + + async def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> List[AuthUser]: + pass + + async def get_auth_user_by_email_async(self, email: str) -> AuthUser: + pass + + async def find_auth_user_by_email_async(self, email: str) -> AuthUser: + pass + + async def add_auth_user_async(self, user_dto: AuthUserDTO) -> AuthUser: + pass + + async def confirm_email_async(self, id: str) -> AuthUser: + pass + + async def login_async(self, user_dto: AuthUserDTO) -> AuthUser: + pass + + async def forgot_password_async(self, email: str) -> AuthUser: + pass + + async def confirm_forgot_password_async(self, id: str) -> AuthUser: + pass + + async def reset_password_async(self, rp_dto: ResetPasswordDTO) -> AuthUser: + pass + + async def update_user_async(self, update_user_dto: UpdateAuthUserDTO) -> AuthUser: + pass + + async def update_user_as_admin_async(self, update_user_dto: UpdateAuthUserDTO) -> AuthUser: + pass + + async def refresh_async(self, token_dto: TokenDTO) -> AuthUser: + pass + + async def revoke_async(self, token_dto: TokenDTO) -> AuthUser: + pass + + async def delete_auth_user_by_email_async(self, email: str) -> AuthUser: + pass + + async def delete_auth_user_async(self, user_dto: AuthUserDTO) -> AuthUser: + pass From 1defe29406fa5a9ebda3db20a15057237ea2c422 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Fri, 14 Oct 2022 15:37:52 +0200 Subject: [PATCH 009/102] Added auth user controller #70 --- src/bot_api/abc/auth_service_abc.py | 28 +++--- src/bot_api/api.py | 1 - src/bot_api/api_module.py | 3 + src/bot_api/controller/auth_controller.py | 97 ++++++++++++++++--- src/bot_api/json_processor.py | 32 ++++++ src/bot_api/model/auth_user_dto.py | 42 +++++--- .../model/auth_user_filtered_result_dto.py | 21 ++++ src/bot_api/model/email_string_dto.py | 18 ++++ src/bot_api/route/route.py | 20 ++++ src/bot_api/service/auth_service.py | 15 ++- 10 files changed, 232 insertions(+), 45 deletions(-) create mode 100644 src/bot_api/json_processor.py create mode 100644 src/bot_api/model/auth_user_filtered_result_dto.py create mode 100644 src/bot_api/model/email_string_dto.py diff --git a/src/bot_api/abc/auth_service_abc.py b/src/bot_api/abc/auth_service_abc.py index c34af36997..45788c9a52 100644 --- a/src/bot_api/abc/auth_service_abc.py +++ b/src/bot_api/abc/auth_service_abc.py @@ -4,6 +4,8 @@ from cpl_query.extension import List from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria from bot_api.model.auth_user_dto import AuthUserDTO +from bot_api.model.auth_user_filtered_result_dto import AuthUserFilteredResultDTO +from bot_api.model.email_string_dto import EMailStringDTO from bot_api.model.reset_password_dto import ResetPasswordDTO from bot_api.model.token_dto import TokenDTO from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO @@ -19,7 +21,7 @@ class AuthServiceABC(ABC): async def get_all_auth_users_async(self) -> List[AuthUser]: pass @abstractmethod - async def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> List[AuthUser]: pass + async def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> AuthUserFilteredResultDTO: pass @abstractmethod async def get_auth_user_by_email_async(self, email: str) -> AuthUser: pass @@ -28,37 +30,37 @@ class AuthServiceABC(ABC): async def find_auth_user_by_email_async(self, email: str) -> AuthUser: pass @abstractmethod - async def add_auth_user_async(self, user_dto: AuthUserDTO) -> AuthUser: pass + async def add_auth_user_async(self, user_dto: AuthUserDTO) -> int: pass @abstractmethod - async def confirm_email_async(self, id: str) -> AuthUser: pass + async def confirm_email_async(self, id: str) -> bool: pass @abstractmethod - async def login_async(self, user_dto: AuthUserDTO) -> AuthUser: pass + async def login_async(self, user_dto: AuthUserDTO) -> TokenDTO: pass @abstractmethod - async def forgot_password_async(self, email: str) -> AuthUser: pass + async def forgot_password_async(self, email: str): pass @abstractmethod - async def confirm_forgot_password_async(self, id: str) -> AuthUser: pass + async def confirm_forgot_password_async(self, id: str) -> EMailStringDTO: pass @abstractmethod - async def reset_password_async(self, rp_dto: ResetPasswordDTO) -> AuthUser: pass + async def reset_password_async(self, rp_dto: ResetPasswordDTO): pass @abstractmethod - async def update_user_async(self, update_user_dto: UpdateAuthUserDTO) -> AuthUser: pass + async def update_user_async(self, update_user_dto: UpdateAuthUserDTO): pass @abstractmethod - async def update_user_as_admin_async(self, update_user_dto: UpdateAuthUserDTO) -> AuthUser: pass + async def update_user_as_admin_async(self, update_user_dto: UpdateAuthUserDTO): pass @abstractmethod - async def refresh_async(self, token_dto: TokenDTO) -> AuthUser: pass + async def refresh_async(self, token_dto: TokenDTO) -> TokenDTO: pass @abstractmethod - async def revoke_async(self, token_dto: TokenDTO) -> AuthUser: pass + async def revoke_async(self, token_dto: TokenDTO): pass @abstractmethod - async def delete_auth_user_by_email_async(self, email: str) -> AuthUser: pass + async def delete_auth_user_by_email_async(self, email: str): pass @abstractmethod - async def delete_auth_user_async(self, user_dto: AuthUserDTO) -> AuthUser: pass + async def delete_auth_user_async(self, user_dto: AuthUserDTO): pass diff --git a/src/bot_api/api.py b/src/bot_api/api.py index 29c176fa5e..8760377bbe 100644 --- a/src/bot_api/api.py +++ b/src/bot_api/api.py @@ -54,7 +54,6 @@ class Api(Flask): self._logger.debug(__name__, f'Received GET @{request.url}') headers = str(request.headers).replace("\n", "\n\t") self._logger.trace(__name__, f'Headers: \n\t{headers}') - self._logger.trace(__name__, f'Body: {request.get_json(force=True, silent=True)}') def start(self): self._logger.info(__name__, f'Starting API {self._apt_settings.host}:{self._apt_settings.port}') diff --git a/src/bot_api/api_module.py b/src/bot_api/api_module.py index be126e6550..ff1be35b2e 100644 --- a/src/bot_api/api_module.py +++ b/src/bot_api/api_module.py @@ -7,10 +7,12 @@ from cpl_core.mailing import EMailClientABC, EMailClient from cpl_discord.service.discord_collection_abc import DiscordCollectionABC from flask import Flask +from bot_api.abc.auth_service_abc import AuthServiceABC from bot_api.api import Api from bot_api.api_thread import ApiThread from bot_api.controller.api_controller import ApiController from bot_api.controller.auth_controller import AuthController +from bot_api.service.auth_service import AuthService from bot_core.abc.module_abc import ModuleABC from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum @@ -34,5 +36,6 @@ class ApiModule(ModuleABC): services.add_singleton(ApiThread) services.add_singleton(Flask, Api) + services.add_transient(AuthServiceABC, AuthService) services.add_transient(AuthController) services.add_transient(ApiController) diff --git a/src/bot_api/controller/auth_controller.py b/src/bot_api/controller/auth_controller.py index 40427bdab5..adb6f3a249 100644 --- a/src/bot_api/controller/auth_controller.py +++ b/src/bot_api/controller/auth_controller.py @@ -1,19 +1,22 @@ from cpl_core.configuration import ConfigurationABC from cpl_core.environment import ApplicationEnvironmentABC from cpl_core.mailing import EMailClientABC, EMailClientSettings -from cpl_query.extension import List from cpl_translation import TranslatePipe -from flask import request -from flask_cors import cross_origin +from flask import request, jsonify, Response +from bot_api.abc.auth_service_abc import AuthServiceABC from bot_api.api import Api +from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria +from bot_api.json_processor import JSONProcessor from bot_api.logging.api_logger import ApiLogger +from bot_api.model.auth_user_dto import AuthUserDTO from bot_api.model.token_dto import TokenDTO +from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO from bot_api.route.route import Route -from bot_data.model.auth_user import AuthUser class AuthController: + BasePath = '/api/auth' def __init__( self, @@ -23,7 +26,8 @@ class AuthController: t: TranslatePipe, api: Api, mail_settings: EMailClientSettings, - mailer: EMailClientABC + mailer: EMailClientABC, + auth_service: AuthServiceABC ): self._config = config self._env = env @@ -32,16 +36,79 @@ class AuthController: self._api = api self._mail_settings = mail_settings self._mailer = mailer + self._auth_service = auth_service - @Route.route('/api/auth/get-all-users') - async def get_all_users(self) -> List[AuthUser]: - pass + @Route.get(f'{BasePath}/users') + async def get_all_users(self) -> Response: + return jsonify(await self._auth_service.get_all_auth_users_async()) - @Route.route('/api/auth/get-filtered-users', methods=['POST']) - async def get_filtered_users(self) -> List[AuthUser]: - pass + @Route.post(f'{BasePath}/users/get/filtered') + async def get_filtered_users(self) -> Response: + dto: AuthUserSelectCriteria = JSONProcessor.process(AuthUserSelectCriteria, request.get_json(force=True, silent=True)) + result = await self._auth_service.get_filtered_auth_users_async(dto) + return jsonify(result.to_dict()) - @Route.route('/api/auth/login', methods=['POST']) - async def login(self) -> dict: - self._logger.warn(__name__, f'Received {request.json}') - return TokenDTO().to_dict() + @Route.get(f'{BasePath}/users/get/') + async def get_user_from_email(self, email: str) -> Response: + return jsonify(await self._auth_service.get_auth_user_by_email_async(email)) + + @Route.get(f'{BasePath}/users/find/') + async def find_user_from_email(self, email: str) -> Response: + return jsonify(await self._auth_service.find_auth_user_by_email_async(email)) + + @Route.post(f'{BasePath}/register') + async def register(self): + dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True)) + await self._auth_service.add_auth_user_async(dto) + return '', 200 + + @Route.post(f'{BasePath}/login') + async def login(self) -> Response: + dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True)) + result = await self._auth_service.login_async(dto) + return jsonify(result.to_dict()) + + @Route.post(f'{BasePath}/forgot-password/') + async def forgot_password(self, email: str): + await self._auth_service.forgot_password_async(email) + return '', 200 + + @Route.post(f'{BasePath}/confirm-forgot-password/') + async def confirm_forgot_password(self, id: str): + await self._auth_service.confirm_forgot_password_async(id) + return '', 200 + + @Route.post(f'{BasePath}/update-user') + async def update_user(self): + dto: UpdateAuthUserDTO = JSONProcessor.process(UpdateAuthUserDTO, request.get_json(force=True, silent=True)) + await self._auth_service.update_user_async(dto) + return '', 200 + + @Route.post(f'{BasePath}/update-user-as-admin') + async def update_user_as_admin(self): + dto: UpdateAuthUserDTO = JSONProcessor.process(UpdateAuthUserDTO, request.get_json(force=True, silent=True)) + await self._auth_service.update_user_async(dto) + return '', 200 + + @Route.post(f'{BasePath}/refresh') + async def refresh(self) -> Response: + dto: TokenDTO = JSONProcessor.process(TokenDTO, request.get_json(force=True, silent=True)) + result = await self._auth_service.refresh_async(dto) + return jsonify(result.to_dict()) + + @Route.post(f'{BasePath}/revoke') + async def revoke(self): + dto: TokenDTO = JSONProcessor.process(TokenDTO, request.get_json(force=True, silent=True)) + await self._auth_service.revoke_async(dto) + return '', 200 + + @Route.post(f'{BasePath}/delete-user') + async def delete_user(self): + dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True)) + await self._auth_service.delete_auth_user_async(dto) + return '', 200 + + @Route.post(f'{BasePath}/delete-user-by-mail/') + async def delete_user_by_mail(self, email: str): + await self._auth_service.delete_auth_user_by_email_async(email) + return '', 200 diff --git a/src/bot_api/json_processor.py b/src/bot_api/json_processor.py new file mode 100644 index 0000000000..e629258ecf --- /dev/null +++ b/src/bot_api/json_processor.py @@ -0,0 +1,32 @@ +from inspect import signature, Parameter + +from cpl_core.utils import String + + +class JSONProcessor: + + @staticmethod + def process(_t: type, values: dict) -> object: + args = [] + + sig = signature(_t.__init__) + for param in sig.parameters.items(): + parameter = param[1] + if parameter.name == 'self' or parameter.annotation == Parameter.empty: + continue + + name = String.convert_to_camel_case(parameter.name) + name_first_lower = String.first_to_lower(name) + if name in values or name_first_lower in values: + if name in values: + args.append(values[name]) + else: + args.append(values[name_first_lower]) + + elif parameter.default != Parameter.empty: + args.append(parameter.default) + + else: + args.append(None) + + return _t(*args) diff --git a/src/bot_api/model/auth_user_dto.py b/src/bot_api/model/auth_user_dto.py index 7ca44a9e6c..8d7bce2b93 100644 --- a/src/bot_api/model/auth_user_dto.py +++ b/src/bot_api/model/auth_user_dto.py @@ -14,7 +14,7 @@ class AuthUserDTO(DtoABC): id: int, first_name: str, last_name: str, - email: str, + e_mail: str, password: str, confirmation_id: Optional[str], auth_role: AuthRoleEnum, @@ -24,20 +24,38 @@ class AuthUserDTO(DtoABC): self._id = id self._first_name = first_name self._last_name = last_name - self._email = email + self._email = e_mail self._password = password self._is_confirmed = confirmation_id is None self._auth_role = auth_role - - """ - long Id { get; set; } - string FirstName { get; set; } - string LastName { get; set; } - string EMail { get; set; } - string Password { get; set; } - bool IsConfirmed { get; set; } - AuthRoles AuthRole { get; set; } - """ + + @property + def id(self) -> int: + return self._id + + @property + def first_name(self) -> str: + return self._first_name + + @property + def last_name(self) -> str: + return self._last_name + + @property + def email(self) -> str: + return self._email + + @property + def password(self) -> str: + return self._password + + @property + def is_confirmed(self) -> bool: + return self._is_confirmed + + @property + def auth_role(self) -> AuthRoleEnum: + return self._auth_role def from_dict(self, values: dict): self._id = values['Id'] diff --git a/src/bot_api/model/auth_user_filtered_result_dto.py b/src/bot_api/model/auth_user_filtered_result_dto.py new file mode 100644 index 0000000000..6edbdb4462 --- /dev/null +++ b/src/bot_api/model/auth_user_filtered_result_dto.py @@ -0,0 +1,21 @@ +from cpl_query.extension import List + +from bot_api.abc.dto_abc import DtoABC +from bot_data.filtered_result import FilteredResult + + +class AuthUserFilteredResultDTO(DtoABC, FilteredResult): + + def __init__(self, result: List = None, total_count: int = 0): + DtoABC.__init__(self) + FilteredResult.__init__(self, result, total_count) + + def from_dict(self, values: dict): + self._result = values['Users'] + self._total_count = values['TotalCount'] + + def to_dict(self) -> dict: + return { + 'Users': self.result, + 'TotalCount': self.total_count + } diff --git a/src/bot_api/model/email_string_dto.py b/src/bot_api/model/email_string_dto.py new file mode 100644 index 0000000000..bc70239dc4 --- /dev/null +++ b/src/bot_api/model/email_string_dto.py @@ -0,0 +1,18 @@ +import traceback + +from cpl_core.console import Console + +from bot_api.abc.dto_abc import DtoABC + + +class EMailStringDTO(DtoABC): + + def __init__(self): + DtoABC.__init__(self) + + def from_dict(self, values: dict): + pass + + def to_dict(self) -> dict: + return { + } diff --git a/src/bot_api/route/route.py b/src/bot_api/route/route.py index 9dbe7fcbfa..fbf1a9f8dc 100644 --- a/src/bot_api/route/route.py +++ b/src/bot_api/route/route.py @@ -9,3 +9,23 @@ class Route: return fn return inner + + @classmethod + def get(cls, path=None, **kwargs): + return cls.route(path, methods=['GET'], **kwargs) + + @classmethod + def post(cls, path=None, **kwargs): + return cls.route(path, methods=['POST'], **kwargs) + + @classmethod + def head(cls, path=None, **kwargs): + return cls.route(path, methods=['HEAD'], **kwargs) + + @classmethod + def put(cls, path=None, **kwargs): + return cls.route(path, methods=['PUT'], **kwargs) + + @classmethod + def delete(cls, path=None, **kwargs): + return cls.route(path, methods=['DELETE'], **kwargs) diff --git a/src/bot_api/service/auth_service.py b/src/bot_api/service/auth_service.py index 3455c08328..7aa072dc04 100644 --- a/src/bot_api/service/auth_service.py +++ b/src/bot_api/service/auth_service.py @@ -2,7 +2,9 @@ from cpl_query.extension import List from bot_api.abc.auth_service_abc import AuthServiceABC from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria +from bot_api.logging.api_logger import ApiLogger from bot_api.model.auth_user_dto import AuthUserDTO +from bot_api.model.auth_user_filtered_result_dto import AuthUserFilteredResultDTO from bot_api.model.reset_password_dto import ResetPasswordDTO from bot_api.model.token_dto import TokenDTO from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO @@ -11,13 +13,18 @@ from bot_data.model.auth_user import AuthUser class AuthService(AuthServiceABC): - def __init__(self): - pass + def __init__( + self, + logger: ApiLogger, + ): + AuthServiceABC.__init__(self) + + self._logger = logger async def get_all_auth_users_async(self) -> List[AuthUser]: pass - async def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> List[AuthUser]: + async def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> AuthUserFilteredResultDTO: pass async def get_auth_user_by_email_async(self, email: str) -> AuthUser: @@ -32,7 +39,7 @@ class AuthService(AuthServiceABC): async def confirm_email_async(self, id: str) -> AuthUser: pass - async def login_async(self, user_dto: AuthUserDTO) -> AuthUser: + async def login_async(self, user_dto: AuthUserDTO) -> TokenDTO: pass async def forgot_password_async(self, email: str) -> AuthUser: From 1090e502c26b11f67e26c47adaf01488e39f6579 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Fri, 14 Oct 2022 23:32:36 +0200 Subject: [PATCH 010/102] [WIP] Added auth service stuff without jwt #70 --- src/bot/translation/de.json | 12 +- src/bot_api/abc/auth_user_transformer_abc.py | 16 ++ src/bot_api/bot-api.json | 1 + src/bot_api/model/email_string_dto.py | 7 +- src/bot_api/model/reset_password_dto.py | 18 +- src/bot_api/model/update_auth_user_dto.py | 31 ++- src/bot_api/service/auth_service.py | 256 ++++++++++++++++-- src/bot_api/transformer/__init__.py | 0 .../transformer/auth_user_transformer.py | 33 +++ src/bot_data/abc/auth_user_repository_abc.py | 10 +- src/bot_data/model/auth_user.py | 60 +++- .../service/auth_user_repository_service.py | 10 +- 12 files changed, 407 insertions(+), 47 deletions(-) create mode 100644 src/bot_api/abc/auth_user_transformer_abc.py create mode 100644 src/bot_api/transformer/__init__.py create mode 100644 src/bot_api/transformer/auth_user_transformer.py diff --git a/src/bot/translation/de.json b/src/bot/translation/de.json index 03b69e95c9..5ffe9dcf36 100644 --- a/src/bot/translation/de.json +++ b/src/bot/translation/de.json @@ -159,6 +159,16 @@ "subject": "Krümmelmonster Web Interface Test-Mail", "message": "Dies ist eine Test-Mail vom Krümmelmonster Web Interface\nGesendet von {}-{}" } - } + }, + "auth": { + "confirmation": { + "subject": "E-Mail für {} {} bestätigen", + "message": "Öffne den Link um die E-Mail zu bestätigen:\n{}auth/forgot-password/{}" + }, + "forgot_password": { + "subject": "Passwort für {} {} zurücksetzen", + "message": "Öffne den Link um das Passwort zu ändern:\n{}auth/forgot-password/{}" + } + } } } \ No newline at end of file diff --git a/src/bot_api/abc/auth_user_transformer_abc.py b/src/bot_api/abc/auth_user_transformer_abc.py new file mode 100644 index 0000000000..fd273847c5 --- /dev/null +++ b/src/bot_api/abc/auth_user_transformer_abc.py @@ -0,0 +1,16 @@ +from abc import abstractmethod + +from cpl_core.database import TableABC + +from bot_api.abc.dto_abc import DtoABC + + +class AuthUserTransformerABC: + + @staticmethod + @abstractmethod + def to_db(dto: DtoABC) -> TableABC: pass + + @staticmethod + @abstractmethod + def to_dto(db: TableABC) -> DtoABC: pass diff --git a/src/bot_api/bot-api.json b/src/bot_api/bot-api.json index 7b66f8efe5..a807eeb181 100644 --- a/src/bot_api/bot-api.json +++ b/src/bot_api/bot-api.json @@ -21,6 +21,7 @@ "Flask[async]==2.2.2", "Flask-Classful==0.14.2", "Flask-Cors==3.0.10", + "PyJWT[crypto]==2.5.0", "PyJWT==2.5.0" ], "DevDependencies": [ diff --git a/src/bot_api/model/email_string_dto.py b/src/bot_api/model/email_string_dto.py index bc70239dc4..1f5ef08738 100644 --- a/src/bot_api/model/email_string_dto.py +++ b/src/bot_api/model/email_string_dto.py @@ -7,12 +7,15 @@ from bot_api.abc.dto_abc import DtoABC class EMailStringDTO(DtoABC): - def __init__(self): + def __init__(self, email: str): DtoABC.__init__(self) + self._email = email + def from_dict(self, values: dict): - pass + self._email = values['EMail'] def to_dict(self) -> dict: return { + 'EMail': self._email } diff --git a/src/bot_api/model/reset_password_dto.py b/src/bot_api/model/reset_password_dto.py index 240437cdfa..0bacce596e 100644 --- a/src/bot_api/model/reset_password_dto.py +++ b/src/bot_api/model/reset_password_dto.py @@ -7,12 +7,26 @@ from bot_api.abc.dto_abc import DtoABC class ResetPasswordDTO(DtoABC): - def __init__(self): + def __init__(self, id: str, password: str): DtoABC.__init__(self) + self._id = id + self._password = password + + @property + def id(self) -> str: + return self._id + + @property + def password(self) -> str: + return self._password + def from_dict(self, values: dict): - pass + self._id = values['Id'] + self._password = values['Password'] def to_dict(self) -> dict: return { + 'Id': self._id, + 'Password': self._password } diff --git a/src/bot_api/model/update_auth_user_dto.py b/src/bot_api/model/update_auth_user_dto.py index b7d501f587..7c481330a4 100644 --- a/src/bot_api/model/update_auth_user_dto.py +++ b/src/bot_api/model/update_auth_user_dto.py @@ -3,16 +3,43 @@ import traceback from cpl_core.console import Console from bot_api.abc.dto_abc import DtoABC +from bot_api.model.auth_user_dto import AuthUserDTO class UpdateAuthUserDTO(DtoABC): - def __init__(self): + def __init__( + self, + auth_user: AuthUserDTO, + new_auth_user: AuthUserDTO, + change_password=False + ): DtoABC.__init__(self) + self._auth_user = auth_user + self._new_auth_user = new_auth_user + self._change_password = change_password + + @property + def auth_user(self) -> AuthUserDTO: + return self._auth_user + + @property + def new_auth_user(self) -> AuthUserDTO: + return self._new_auth_user + + @property + def change_password(self) -> bool: + return self._change_password + def from_dict(self, values: dict): - pass + self._auth_user = values['AuthUser'] + self._new_auth_user = values['NewAuthUser'] + self._change_password = False if 'ChangePassword' not in values else values['ChangePassword'] def to_dict(self) -> dict: return { + 'AuthUser': self._auth_user, + 'NewAuthUser': self._new_auth_user, + 'ChangePassword': self._change_password } diff --git a/src/bot_api/service/auth_service.py b/src/bot_api/service/auth_service.py index 7aa072dc04..05283d4e60 100644 --- a/src/bot_api/service/auth_service.py +++ b/src/bot_api/service/auth_service.py @@ -1,13 +1,25 @@ +import hashlib +import re +import uuid +from typing import Optional + +from cpl_core.database.context import DatabaseContextABC +from cpl_core.mailing import EMailClientABC, EMail from cpl_query.extension import List +from cpl_translation import TranslatePipe from bot_api.abc.auth_service_abc import AuthServiceABC +from bot_api.configuration.frontend_settings import FrontendSettings from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria from bot_api.logging.api_logger import ApiLogger -from bot_api.model.auth_user_dto import AuthUserDTO +from bot_api.model.auth_user import AuthUserDTO from bot_api.model.auth_user_filtered_result_dto import AuthUserFilteredResultDTO +from bot_api.model.email_string_dto import EMailStringDTO from bot_api.model.reset_password_dto import ResetPasswordDTO from bot_api.model.token_dto import TokenDTO from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO +from bot_api.transformer.auth_user_transformer import AuthUserTransformer as AUT +from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC from bot_data.model.auth_user import AuthUser @@ -16,46 +28,235 @@ class AuthService(AuthServiceABC): def __init__( self, logger: ApiLogger, + auth_users: AuthUserRepositoryABC, + db: DatabaseContextABC, + mailer: EMailClientABC, + t: TranslatePipe, + frontend_settings: FrontendSettings, + ): AuthServiceABC.__init__(self) self._logger = logger + self._auth_users = auth_users + self._db = db + self._mailer = mailer + self._t = t + self._frontend_settings = frontend_settings + + @staticmethod + def _get_mail_to_send() -> EMail: + mail = EMail() + mail.add_header('Mime-Version: 1.0') + mail.add_header('Content-Type: text/plain charset=utf-8') + mail.add_header('Content-Transfer-Encoding: quoted-printable') + return mail + + @staticmethod + def _hash_sha256(password: str) -> str: + return hashlib.sha256(password.encode('utf-8')).hexdigest() + + @staticmethod + def _is_email_valid(email: str) -> bool: + regex = '^[a-z0-9]+[\\._]?[a-z0-9]+[@]\\w+[.]\\w{2,3}$' + return bool(re.search(regex, email)) + + def _send_confirmation_id_to_user(self, user: AuthUser): + url = self._frontend_settings.url + if not url.endswith('/'): + url = f'{url}/' + + mail = self._get_mail_to_send() + mail.add_receiver(user.email) + mail.subject = self._t.transform('api.auth.confirmation.subject').format(user.first_name, user.last_name) + mail.body = self._t.transform('api.auth.confirmation.message').format(url, user.confirmation_id) + self._mailer.send_mail(mail) + + def _send_forgot_password_id_to_user(self, user: AuthUser): + url = self._frontend_settings.url + if not url.endswith('/'): + url = f'{url}/' + + mail = self._get_mail_to_send() + mail.add_receiver(user.email) + mail.subject = self._t.transform('api.auth.forgot_password.subject').format(user.first_name, user.last_name) + mail.body = self._t.transform('api.auth.forgot_password.message').format(url, user.forgot_password_id) + self._mailer.send_mail(mail) async def get_all_auth_users_async(self) -> List[AuthUser]: - pass + result = self._auth_users.get_all_auth_users() \ + .select(lambda x: AUT.to_dto(x)) + return List(AuthUserDTO, result) async def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> AuthUserFilteredResultDTO: - pass + users = self._auth_users.get_filtered_auth_users(criteria) + result = users.result.select(lambda x: AUT.to_dto(x)) + + return AuthUserFilteredResultDTO( + List(AuthUserDTO, result), + users.total_count + ) async def get_auth_user_by_email_async(self, email: str) -> AuthUser: - pass + try: + user = self._auth_users.get_auth_user_by_email(email) + return user + except Exception as e: + self._logger.error(__name__, f'AuthUser not found', e) + raise Exception(f'User not found {email}') - async def find_auth_user_by_email_async(self, email: str) -> AuthUser: - pass + async def find_auth_user_by_email_async(self, email: str) -> Optional[AuthUser]: + user = self._auth_users.find_auth_user_by_email(email) + return AUT.to_dto(user) if user is not None else None async def add_auth_user_async(self, user_dto: AuthUserDTO) -> AuthUser: pass - async def confirm_email_async(self, id: str) -> AuthUser: - pass + async def confirm_email_async(self, id: str) -> bool: + user = self._auth_users.find_auth_user_by_confirmation_id(id) + if user is None: + return False + + user.confirmation_id = None + self._auth_users.update_auth_user(user) + self._db.save_changes() + return True async def login_async(self, user_dto: AuthUserDTO) -> TokenDTO: pass - async def forgot_password_async(self, email: str) -> AuthUser: - pass + async def forgot_password_async(self, email: str): + user = self._auth_users.find_auth_user_by_email(email) + if user is None: + return - async def confirm_forgot_password_async(self, id: str) -> AuthUser: - pass + user.forgot_password_id = uuid.uuid4() + self._auth_users.update_auth_user(user) + self._send_forgot_password_id_to_user(user) + self._db.save_changes() - async def reset_password_async(self, rp_dto: ResetPasswordDTO) -> AuthUser: - pass + async def confirm_forgot_password_async(self, id: str) -> EMailStringDTO: + user = self._auth_users.find_auth_user_by_forgot_password_id(id) + return EMailStringDTO(user.email) - async def update_user_async(self, update_user_dto: UpdateAuthUserDTO) -> AuthUser: - pass + async def reset_password_async(self, rp_dto: ResetPasswordDTO): + user = self._auth_users.find_auth_user_by_forgot_password_id(rp_dto.id) + if user is None: + pass - async def update_user_as_admin_async(self, update_user_dto: UpdateAuthUserDTO) -> AuthUser: - pass + if user.confirmation_id is not None: + pass + + if user.password is None or rp_dto.password == '': + pass + + user.password = self._hash_sha256(rp_dto.password) + self._db.save_changes() + + async def update_user_async(self, update_user_dto: UpdateAuthUserDTO): + if update_user_dto is None: + raise Exception(f'User is empty') + + if update_user_dto.auth_user is None: + raise Exception(f'Existing user is empty') + + if update_user_dto.new_auth_user is None: + raise Exception(f'New user is empty') + + if not self._is_email_valid(update_user_dto.auth_user.email) or not self._is_email_valid(update_user_dto.new_auth_user.email): + raise Exception(f'Invalid E-Mail') + + user = self._auth_users.find_auth_user_by_email(update_user_dto.auth_user.email) + if user is None: + raise Exception('User not found') + + if user.confirmation_id is not None: + raise Exception('E-Mail not confirmed') + + # update first name + if update_user_dto.new_auth_user.first_name is not None and update_user_dto.auth_user.first_name != update_user_dto.new_auth_user.first_name: + user.FirstName = update_user_dto.new_auth_user.first_name + + # update last name + if update_user_dto.new_auth_user.last_name is not None and update_user_dto.new_auth_user.last_name != '' and \ + update_user_dto.auth_user.last_name != update_user_dto.new_auth_user.last_name: + user.LastName = update_user_dto.new_auth_user.last_name + + # update E-Mail + if update_user_dto.new_auth_user.email is not None and update_user_dto.new_auth_user.email != '' and update_user_dto.auth_user.email != update_user_dto.new_auth_user.email: + user_by_new_e_mail = self._auth_users.find_auth_user_by_email(update_user_dto.new_auth_user.email) + if user_by_new_e_mail is not None: + raise Exception('User already exists') + user.email = update_user_dto.new_auth_user.email + + is_existing_password_set = False + is_new_password_set = False + # hash passwords in DTOs + if update_user_dto.auth_user.Password is not None and update_user_dto.auth_user.Password != '': + is_existing_password_set = True + update_user_dto.auth_user.Password = self._hash_sha256(update_user_dto.auth_user.Password) + + if update_user_dto.auth_user.Password != user.Password: + raise Exception('Wrong password') + + if update_user_dto.new_auth_user.Password is not None and update_user_dto.new_auth_user.Password != '': + is_new_password_set = True + update_user_dto.new_auth_user.Password = self._hash_sha256(update_user_dto.new_auth_user.Password) + + # update password + if is_existing_password_set and is_new_password_set and update_user_dto.auth_user.Password != update_user_dto.new_auth_user.Password: + user.Password = update_user_dto.new_auth_user.Password + + self._db.save_changes() + + async def update_user_as_admin_async(self, update_user_dto: UpdateAuthUserDTO): + if update_user_dto is None: + raise Exception(f'User is empty') + + if update_user_dto.auth_user is None: + raise Exception(f'Existing user is empty') + + if update_user_dto.new_auth_user is None: + raise Exception(f'New user is empty') + + if not self._is_email_valid(update_user_dto.auth_user.email) or not self._is_email_valid(update_user_dto.new_auth_user.email): + raise Exception(f'Invalid E-Mail') + + user = self._auth_users.find_auth_user_by_email(update_user_dto.auth_user.email) + if user is None: + raise Exception('User not found') + + if user.ConfirmationId is not None and update_user_dto.new_auth_user.is_confirmed: + user.ConfirmationId = None + elif user.ConfirmationId is None and not update_user_dto.new_auth_user.is_confirmed: + user.confirmation_id = uuid.uuid4() + # else + # raise Exception(ServiceErrorCode.InvalidUser, 'E-Mail not confirmed') + + # update first name + if update_user_dto.new_auth_user.first_name is not None and update_user_dto.auth_user.first_name != update_user_dto.new_auth_user.first_name: + user.FirstName = update_user_dto.new_auth_user.first_name + + # update last name + if update_user_dto.new_auth_user.last_name is not None and update_user_dto.new_auth_user.last_name != '' and update_user_dto.auth_user.last_name != update_user_dto.new_auth_user.last_name: + user.LastName = update_user_dto.new_auth_user.last_name + + # update E-Mail + if update_user_dto.new_auth_user.email is not None and update_user_dto.new_auth_user.email != '' and update_user_dto.auth_user.email != update_user_dto.new_auth_user.email: + user_by_new_e_mail = self._auth_users.find_auth_user_by_email(update_user_dto.new_auth_user.email) + if user_by_new_e_mail is not None: + raise Exception('User already exists') + user.EMail = update_user_dto.new_auth_user.email + + # update password + if update_user_dto.change_password and update_user_dto.auth_user.password != update_user_dto.new_auth_user.password: + user.Password = self._hash_sha256(update_user_dto.new_auth_user.password) + + # update role + if user.auth_role == update_user_dto.auth_user.auth_role and user.auth_role != update_user_dto.new_auth_user.auth_role: + user.auth_role = update_user_dto.new_auth_user.auth_role + + self._db.save_changes() async def refresh_async(self, token_dto: TokenDTO) -> AuthUser: pass @@ -63,8 +264,19 @@ class AuthService(AuthServiceABC): async def revoke_async(self, token_dto: TokenDTO) -> AuthUser: pass - async def delete_auth_user_by_email_async(self, email: str) -> AuthUser: - pass + async def delete_auth_user_by_email_async(self, email: str): + try: + user = self._auth_users.get_auth_user_by_email(email) + self._auth_users.delete_auth_user(user) + self._db.save_changes() + except Exception as e: + self._logger.error(__name__, f'Cannot delete user', e) + raise Exception(f'Cannot delete user by mail {email}') - async def delete_auth_user_async(self, user_dto: AuthUserDTO) -> AuthUser: - pass + async def delete_auth_user_async(self, user_dto: AuthUserDTO): + try: + self._auth_users.delete_auth_user(AUT.to_db(user_dto)) + self._db.save_changes() + except Exception as e: + self._logger.error(__name__, f'Cannot delete user', e) + raise Exception(f'Cannot delete user by mail {user_dto.email}') diff --git a/src/bot_api/transformer/__init__.py b/src/bot_api/transformer/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/bot_api/transformer/auth_user_transformer.py b/src/bot_api/transformer/auth_user_transformer.py new file mode 100644 index 0000000000..50258b016e --- /dev/null +++ b/src/bot_api/transformer/auth_user_transformer.py @@ -0,0 +1,33 @@ +from bot_api.abc.auth_user_transformer_abc import AuthUserTransformerABC +from bot_api.model.auth_user_dto import AuthUserDTO +from bot_data.model.auth_user import AuthUser + + +class AuthUserTransformer(AuthUserTransformerABC): + + @staticmethod + def to_db(dto: AuthUserDTO) -> AuthUser: + return AuthUser( + dto.first_name, + dto.last_name, + dto.email, + dto.password, + None, + None, + None, + None, + dto.auth_role, + id=dto.id + ) + + @staticmethod + def to_dto(db: AuthUser) -> AuthUserDTO: + return AuthUserDTO( + db.id, + db.first_name, + db.last_name, + db.email, + db.password, + db.confirmation_id is None, + db.auth_role + ) diff --git a/src/bot_data/abc/auth_user_repository_abc.py b/src/bot_data/abc/auth_user_repository_abc.py index 161187461e..a376a273ac 100644 --- a/src/bot_data/abc/auth_user_repository_abc.py +++ b/src/bot_data/abc/auth_user_repository_abc.py @@ -17,19 +17,19 @@ class AuthUserRepositoryABC(ABC): def get_all_auth_users(self) -> List[AuthUser]: pass @abstractmethod - def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> FilteredResult: pass + def get_filtered_auth_users(self, criteria: AuthUserSelectCriteria) -> FilteredResult: pass @abstractmethod - def get_auth_user_by_email_async(self, email: str) -> AuthUser: pass + def get_auth_user_by_email(self, email: str) -> AuthUser: pass @abstractmethod - def find_auth_user_by_email_async(self, email: str) -> Optional[AuthUser]: pass + def find_auth_user_by_email(self, email: str) -> Optional[AuthUser]: pass @abstractmethod - def find_auth_user_by_confirmation_id_async(self, id: str) -> Optional[AuthUser]: pass + def find_auth_user_by_confirmation_id(self, id: str) -> Optional[AuthUser]: pass @abstractmethod - def find_auth_user_by_forgot_password_id_async(self, id: str) -> Optional[AuthUser]: pass + def find_auth_user_by_forgot_password_id(self, id: str) -> Optional[AuthUser]: pass @abstractmethod def add_auth_user(self, user: AuthUser): pass diff --git a/src/bot_data/model/auth_user.py b/src/bot_data/model/auth_user.py index 6078f2099b..eeb90d76e0 100644 --- a/src/bot_data/model/auth_user.py +++ b/src/bot_data/model/auth_user.py @@ -14,10 +14,10 @@ class AuthUser(TableABC): last_name: str, email: str, password: str, - refresh_token: str, - confirmation_id: str, - forgot_password_id: str, - refresh_token_expire_time: datetime, + refresh_token: Optional[str], + confirmation_id: Optional[str], + forgot_password_id: Optional[str], + refresh_token_expire_time: Optional[datetime], auth_role: AuthRoleEnum, created_at: datetime = None, modified_at: datetime = None, @@ -47,30 +47,74 @@ class AuthUser(TableABC): def first_name(self) -> str: return self._first_name + @first_name.setter + def first_name(self, value: str): + self._first_name = value + @property def last_name(self) -> str: return self._last_name + @last_name.setter + def last_name(self, value: str): + self._last_name = value + @property def email(self) -> str: return self._email + @email.setter + def email(self, value: str): + self._email = value + @property def password(self) -> str: return self._password - @property - def refresh_token(self) -> str: - return self._refresh_token + @password.setter + def password(self, value: str): + self._password = value @property - def refresh_token_expire_time(self) -> datetime: + def refresh_token(self) -> Optional[str]: + return self._refresh_token + + @refresh_token.setter + def refresh_token(self, value: Optional[str]): + self._refresh_token = value + + @property + def confirmation_id(self) -> Optional[str]: + return self._confirmation_id + + @confirmation_id.setter + def confirmation_id(self, value: Optional[str]): + self._confirmation_id = value + + @property + def forgot_password_id(self) -> Optional[str]: + return self._forgot_password_id + + @forgot_password_id.setter + def forgot_password_id(self, value: Optional[str]): + self._forgot_password_id = value + + @property + def refresh_token_expire_time(self) -> Optional[datetime]: return self._refresh_token_expire_time + @refresh_token_expire_time.setter + def refresh_token_expire_time(self, value: Optional[datetime]): + self._refresh_token_expire_time = value + @property def auth_role(self) -> AuthRoleEnum: return self._auth_role_id + @auth_role.setter + def auth_role(self, value: AuthRoleEnum): + self._auth_role_id = value + @staticmethod def get_select_all_string() -> str: return str(f""" diff --git a/src/bot_data/service/auth_user_repository_service.py b/src/bot_data/service/auth_user_repository_service.py index aca3e94af2..2096113e34 100644 --- a/src/bot_data/service/auth_user_repository_service.py +++ b/src/bot_data/service/auth_user_repository_service.py @@ -44,7 +44,7 @@ class AuthUserRepositoryService(AuthUserRepositoryABC): return users - def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> FilteredResult: + def get_filtered_auth_users(self, criteria: AuthUserSelectCriteria) -> FilteredResult: users = self.get_all_auth_users() self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_all_string()}') @@ -77,12 +77,12 @@ class AuthUserRepositoryService(AuthUserRepositoryABC): return result - def get_auth_user_by_email_async(self, email: str) -> AuthUser: + def get_auth_user_by_email(self, email: str) -> AuthUser: self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_by_email_string(email)}') result = self._context.select(AuthUser.get_select_by_email_string(email))[0] return self._user_from_result(result) - def find_auth_user_by_email_async(self, email: str) -> Optional[AuthUser]: + def find_auth_user_by_email(self, email: str) -> Optional[AuthUser]: self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_by_email_string(email)}') result = self._context.select(AuthUser.get_select_by_email_string(email)) if result is None or len(result) == 0: @@ -92,7 +92,7 @@ class AuthUserRepositoryService(AuthUserRepositoryABC): return self._user_from_result(result) - def find_auth_user_by_confirmation_id_async(self, id: str) -> Optional[AuthUser]: + def find_auth_user_by_confirmation_id(self, id: str) -> Optional[AuthUser]: self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_by_email_string(id)}') result = self._context.select(AuthUser.get_select_by_email_string(id)) if result is None or len(result) == 0: @@ -102,7 +102,7 @@ class AuthUserRepositoryService(AuthUserRepositoryABC): return self._user_from_result(result) - def find_auth_user_by_forgot_password_id_async(self, id: str) -> Optional[AuthUser]: + def find_auth_user_by_forgot_password_id(self, id: str) -> Optional[AuthUser]: self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_by_email_string(id)}') result = self._context.select(AuthUser.get_select_by_email_string(id)) if result is None or len(result) == 0: From 6f95d0a055e838a4eb4e98c5d92fd63ba8f6dee2 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 15 Oct 2022 00:42:55 +0200 Subject: [PATCH 011/102] Added auth service stuff with jwt #70 --- src/bot_api/abc/auth_service_abc.py | 38 +++--- src/bot_api/model/auth_user_dto.py | 40 ++++-- src/bot_api/model/token_dto.py | 18 ++- src/bot_api/service/auth_service.py | 185 ++++++++++++++++++++-------- 4 files changed, 204 insertions(+), 77 deletions(-) diff --git a/src/bot_api/abc/auth_service_abc.py b/src/bot_api/abc/auth_service_abc.py index 45788c9a52..e4f611c69f 100644 --- a/src/bot_api/abc/auth_service_abc.py +++ b/src/bot_api/abc/auth_service_abc.py @@ -33,11 +33,29 @@ class AuthServiceABC(ABC): async def add_auth_user_async(self, user_dto: AuthUserDTO) -> int: pass @abstractmethod - async def confirm_email_async(self, id: str) -> bool: pass + async def update_user_async(self, update_user_dto: UpdateAuthUserDTO): pass + + @abstractmethod + async def update_user_as_admin_async(self, update_user_dto: UpdateAuthUserDTO): pass + + @abstractmethod + async def delete_auth_user_by_email_async(self, email: str): pass + + @abstractmethod + async def delete_auth_user_async(self, user_dto: AuthUserDTO): pass @abstractmethod async def login_async(self, user_dto: AuthUserDTO) -> TokenDTO: pass + @abstractmethod + async def refresh_async(self, token_dto: TokenDTO) -> TokenDTO: pass + + @abstractmethod + async def revoke_async(self, token_dto: TokenDTO): pass + + @abstractmethod + async def confirm_email_async(self, id: str) -> bool: pass + @abstractmethod async def forgot_password_async(self, email: str): pass @@ -46,21 +64,3 @@ class AuthServiceABC(ABC): @abstractmethod async def reset_password_async(self, rp_dto: ResetPasswordDTO): pass - - @abstractmethod - async def update_user_async(self, update_user_dto: UpdateAuthUserDTO): pass - - @abstractmethod - async def update_user_as_admin_async(self, update_user_dto: UpdateAuthUserDTO): pass - - @abstractmethod - async def refresh_async(self, token_dto: TokenDTO) -> TokenDTO: pass - - @abstractmethod - async def revoke_async(self, token_dto: TokenDTO): pass - - @abstractmethod - async def delete_auth_user_by_email_async(self, email: str): pass - - @abstractmethod - async def delete_auth_user_async(self, user_dto: AuthUserDTO): pass diff --git a/src/bot_api/model/auth_user_dto.py b/src/bot_api/model/auth_user_dto.py index 8d7bce2b93..304ce047e0 100644 --- a/src/bot_api/model/auth_user_dto.py +++ b/src/bot_api/model/auth_user_dto.py @@ -32,30 +32,54 @@ class AuthUserDTO(DtoABC): @property def id(self) -> int: return self._id - + @property def first_name(self) -> str: return self._first_name - + + @first_name.setter + def first_name(self, value: str): + self._first_name = value + @property def last_name(self) -> str: return self._last_name - + + @last_name.setter + def last_name(self, value: str): + self._last_name = value + @property def email(self) -> str: return self._email - + + @email.setter + def email(self, value: str): + self._email = value + @property def password(self) -> str: return self._password - + + @password.setter + def password(self, value: str): + self._password = value + @property - def is_confirmed(self) -> bool: + def is_confirmed(self) -> Optional[str]: return self._is_confirmed - + + @is_confirmed.setter + def is_confirmed(self, value: Optional[str]): + self._is_confirmed = value + @property def auth_role(self) -> AuthRoleEnum: - return self._auth_role + return self.auth_role + + @auth_role.setter + def auth_role(self, value: AuthRoleEnum): + self.auth_role = value def from_dict(self, values: dict): self._id = values['Id'] diff --git a/src/bot_api/model/token_dto.py b/src/bot_api/model/token_dto.py index 445943c248..987d9ad296 100644 --- a/src/bot_api/model/token_dto.py +++ b/src/bot_api/model/token_dto.py @@ -7,12 +7,26 @@ from bot_api.abc.dto_abc import DtoABC class TokenDTO(DtoABC): - def __init__(self): + def __init__(self, token: str, refresh_token: str): DtoABC.__init__(self) + self._token = token + self._refresh_token = refresh_token + + @property + def token(self) -> str: + return self._token + + @property + def refresh_token(self) -> str: + return self._refresh_token + def from_dict(self, values: dict): - pass + self._token = values['Token'] + self._refresh_token = values['RefreshToken'] def to_dict(self) -> dict: return { + 'Token': self._token, + 'RefreshToken': self._refresh_token } diff --git a/src/bot_api/service/auth_service.py b/src/bot_api/service/auth_service.py index 05283d4e60..472585900b 100644 --- a/src/bot_api/service/auth_service.py +++ b/src/bot_api/service/auth_service.py @@ -1,18 +1,21 @@ import hashlib import re import uuid +from datetime import datetime, timedelta, timezone from typing import Optional +import jwt from cpl_core.database.context import DatabaseContextABC from cpl_core.mailing import EMailClientABC, EMail from cpl_query.extension import List from cpl_translation import TranslatePipe from bot_api.abc.auth_service_abc import AuthServiceABC +from bot_api.configuration.authentication_settings import AuthenticationSettings from bot_api.configuration.frontend_settings import FrontendSettings from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria from bot_api.logging.api_logger import ApiLogger -from bot_api.model.auth_user import AuthUserDTO +from bot_api.model.auth_user_dto import AuthUserDTO from bot_api.model.auth_user_filtered_result_dto import AuthUserFilteredResultDTO from bot_api.model.email_string_dto import EMailStringDTO from bot_api.model.reset_password_dto import ResetPasswordDTO @@ -32,6 +35,7 @@ class AuthService(AuthServiceABC): db: DatabaseContextABC, mailer: EMailClientABC, t: TranslatePipe, + auth_settings: AuthenticationSettings, frontend_settings: FrontendSettings, ): @@ -42,6 +46,7 @@ class AuthService(AuthServiceABC): self._db = db self._mailer = mailer self._t = t + self._auth_settings = auth_settings self._frontend_settings = frontend_settings @staticmethod @@ -61,6 +66,29 @@ class AuthService(AuthServiceABC): regex = '^[a-z0-9]+[\\._]?[a-z0-9]+[@]\\w+[.]\\w{2,3}$' return bool(re.search(regex, email)) + def _generate_token(self, user: AuthUser) -> str: + token = jwt.encode( + payload={ + 'user_id': user.id, + 'email': user.email, + 'role': user.auth_role, + 'exp': datetime.now(tz=timezone.utc) + timedelta(days=self._auth_settings.token_expire_time), + 'iss': self._auth_settings.issuer, + 'aud': self._auth_settings.audience + }, + key=self._auth_settings.secret_key, + ) + + return token + + def _create_and_save_refresh_token(self, user: AuthUser) -> str: + token = str(uuid.uuid4()) + user.refresh_token = token + user.refresh_token_expire_time = datetime.now(tz=timezone.utc) + timedelta(days=self._auth_settings.refresh_token_expire_time) + self._auth_users.update_auth_user(user) + self._db.save_changes() + return token + def _send_confirmation_id_to_user(self, user: AuthUser): url = self._frontend_settings.url if not url.endswith('/'): @@ -109,49 +137,24 @@ class AuthService(AuthServiceABC): user = self._auth_users.find_auth_user_by_email(email) return AUT.to_dto(user) if user is not None else None - async def add_auth_user_async(self, user_dto: AuthUserDTO) -> AuthUser: - pass + async def add_auth_user_async(self, user_dto: AuthUserDTO): + db_user = self._auth_users.find_auth_user_by_email(user_dto.email) + if db_user is not None: + raise Exception('User already exists') - async def confirm_email_async(self, id: str) -> bool: - user = self._auth_users.find_auth_user_by_confirmation_id(id) - if user is None: - return False + user_dto.password = self._hash_sha256(user_dto.password) + user = AUT.to_db(user_dto) + if not self._is_email_valid(user.email): + raise Exception('Invalid E-Mail address') - user.confirmation_id = None - self._auth_users.update_auth_user(user) - self._db.save_changes() - return True - - async def login_async(self, user_dto: AuthUserDTO) -> TokenDTO: - pass - - async def forgot_password_async(self, email: str): - user = self._auth_users.find_auth_user_by_email(email) - if user is None: - return - - user.forgot_password_id = uuid.uuid4() - self._auth_users.update_auth_user(user) - self._send_forgot_password_id_to_user(user) - self._db.save_changes() - - async def confirm_forgot_password_async(self, id: str) -> EMailStringDTO: - user = self._auth_users.find_auth_user_by_forgot_password_id(id) - return EMailStringDTO(user.email) - - async def reset_password_async(self, rp_dto: ResetPasswordDTO): - user = self._auth_users.find_auth_user_by_forgot_password_id(rp_dto.id) - if user is None: - pass - - if user.confirmation_id is not None: - pass - - if user.password is None or rp_dto.password == '': - pass - - user.password = self._hash_sha256(rp_dto.password) - self._db.save_changes() + try: + user.confirmation_id = uuid.uuid4() + self._auth_users.update_auth_user(user) + self._send_confirmation_id_to_user(user) + self._db.save_changes() + self._logger.info(__name__, f'Added auth user with E-Mail: {user_dto.email}') + except Exception as e: + self._logger.error(__name__, f'Cannot add user with E-Mal {user_dto.email}', e) async def update_user_async(self, update_user_dto: UpdateAuthUserDTO): if update_user_dto is None: @@ -258,12 +261,6 @@ class AuthService(AuthServiceABC): self._db.save_changes() - async def refresh_async(self, token_dto: TokenDTO) -> AuthUser: - pass - - async def revoke_async(self, token_dto: TokenDTO) -> AuthUser: - pass - async def delete_auth_user_by_email_async(self, email: str): try: user = self._auth_users.get_auth_user_by_email(email) @@ -280,3 +277,95 @@ class AuthService(AuthServiceABC): except Exception as e: self._logger.error(__name__, f'Cannot delete user', e) raise Exception(f'Cannot delete user by mail {user_dto.email}') + + async def login_async(self, user_dto: AuthUserDTO) -> TokenDTO: + if user_dto is None: + raise Exception('User not set') + + db_user = self._auth_users.find_auth_user_by_email(user_dto.email) + if db_user is None: + raise Exception(f'User with E-Mail {user_dto.email} not found') + + user_dto.password = self._hash_sha256(user_dto.password) + if db_user.password != user_dto.password: + raise Exception('Wrong password') + + token = self._generate_token(user_dto) + refresh_token = self._create_and_save_refresh_token(db_user) + if db_user.forgot_password_id is not None: + db_user.forgot_password_id = None + + self._db.save_changes() + return TokenDTO(token, refresh_token) + + async def refresh_async(self, token_dto: TokenDTO) -> TokenDTO: + if token_dto is None: + raise Exception(f'Token not set') + + token = jwt.decode(token_dto.token, key=self._auth_settings.secret_key) + if token is None or 'email' not in token: + raise Exception('Token invalid') + + try: + user = self._auth_users.get_auth_user_by_email(token) + if user is None or user.refresh_token != token_dto.refresh_token or user.refresh_token_expire_time <= datetime.now(): + raise Exception('Token expired') + + return TokenDTO(self._generate_token(user), self._create_and_save_refresh_token(user)) + except Exception as e: + self._logger.error(__name__, f'Refreshing token failed', e) + return TokenDTO('', '') + + async def revoke_async(self, token_dto: TokenDTO): + if token_dto is None or token_dto.token is None or token_dto.refresh_token is None: + raise Exception('Token not set') + + token = jwt.decode(token_dto.token, key=self._auth_settings.secret_key) + try: + user = self._auth_users.get_auth_user_by_email(token) + if user is None or user.refresh_token != token_dto.refresh_token or user.refresh_token_expire_time <= datetime.now(): + raise Exception('Token expired') + + user.refresh_token = None + self._auth_users.update_auth_user(user) + self._db.save_changes() + except Exception as e: + self._logger.error(__name__, f'Refreshing token failed', e) + + async def confirm_email_async(self, id: str) -> bool: + user = self._auth_users.find_auth_user_by_confirmation_id(id) + if user is None: + return False + + user.confirmation_id = None + self._auth_users.update_auth_user(user) + self._db.save_changes() + return True + + async def forgot_password_async(self, email: str): + user = self._auth_users.find_auth_user_by_email(email) + if user is None: + return + + user.forgot_password_id = uuid.uuid4() + self._auth_users.update_auth_user(user) + self._send_forgot_password_id_to_user(user) + self._db.save_changes() + + async def confirm_forgot_password_async(self, id: str) -> EMailStringDTO: + user = self._auth_users.find_auth_user_by_forgot_password_id(id) + return EMailStringDTO(user.email) + + async def reset_password_async(self, rp_dto: ResetPasswordDTO): + user = self._auth_users.find_auth_user_by_forgot_password_id(rp_dto.id) + if user is None: + raise Exception(f'User by forgot password id {rp_dto.id} not found') + + if user.confirmation_id is not None: + raise Exception(f'E-Mail not confirmed') + + if user.password is None or rp_dto.password == '': + raise Exception(f'Password not set') + + user.password = self._hash_sha256(rp_dto.password) + self._db.save_changes() From e0844a7f9267f484bbe617b89482b69d7cdbc30a Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 15 Oct 2022 03:04:17 +0200 Subject: [PATCH 012/102] [WIP] Improved basics of api #70 --- src/bot/startup_migration_extension.py | 2 + src/bot_api/api.py | 26 +++++-- src/bot_api/exception/__init__.py | 0 .../exception/service_error_code_enum.py | 19 ++++++ src/bot_api/exception/service_exception.py | 13 ++++ src/bot_api/model/error_dto.py | 34 ++++++++++ src/bot_api/route/route.py | 4 ++ src/bot_api/service/auth_service.py | 67 ++++++++++--------- src/bot_data/migration/api_migration.py | 4 +- src/bot_data/model/auth_user.py | 28 ++++---- 10 files changed, 145 insertions(+), 52 deletions(-) create mode 100644 src/bot_api/exception/__init__.py create mode 100644 src/bot_api/exception/service_error_code_enum.py create mode 100644 src/bot_api/exception/service_exception.py create mode 100644 src/bot_api/model/error_dto.py diff --git a/src/bot/startup_migration_extension.py b/src/bot/startup_migration_extension.py index b8f7ff0e37..62d4d39d85 100644 --- a/src/bot/startup_migration_extension.py +++ b/src/bot/startup_migration_extension.py @@ -4,6 +4,7 @@ from cpl_core.dependency_injection import ServiceCollectionABC from cpl_core.environment import ApplicationEnvironmentABC from bot_data.abc.migration_abc import MigrationABC +from bot_data.migration.api_migration import ApiMigration from bot_data.migration.auto_role_migration import AutoRoleMigration from bot_data.migration.initial_migration import InitialMigration from bot_data.service.migration_service import MigrationService @@ -21,3 +22,4 @@ class StartupMigrationExtension(StartupExtensionABC): services.add_transient(MigrationService) services.add_transient(MigrationABC, InitialMigration) services.add_transient(MigrationABC, AutoRoleMigration) # 03.10.2022 #54 - 0.2.2 + services.add_transient(MigrationABC, ApiMigration) # 15.10.2022 #70 - 0.3.0 diff --git a/src/bot_api/api.py b/src/bot_api/api.py index 8760377bbe..6a08c9a612 100644 --- a/src/bot_api/api.py +++ b/src/bot_api/api.py @@ -1,13 +1,16 @@ +import json import sys +import uuid from functools import partial -from blinker import Namespace from cpl_core.dependency_injection import ServiceProviderABC -from flask import Flask, request +from flask import Flask, request, jsonify, Response, make_response from flask_cors import CORS from bot_api.configuration.api_settings import ApiSettings +from bot_api.exception.service_exception import ServiceException from bot_api.logging.api_logger import ApiLogger +from bot_api.model.error_dto import ErrorDTO from bot_api.route.route import Route @@ -33,8 +36,8 @@ class Api(Flask): # register before request self.before_request_funcs.setdefault(None, []).append(self.before_request) - my_signals = Namespace() - notify = my_signals.signal('notify') + exc_class, code = self._get_exc_class_and_code(Exception) + self.error_handler_spec[None][code][exc_class] = self.handle_exception def _register_routes(self): for path, f in Route.registered_routes.items(): @@ -50,6 +53,21 @@ class Api(Flask): partial_f.__name__ = route.__name__ self.route(path, **kwargs)(partial_f) + def handle_exception(self, e: Exception): + self._logger.error(__name__, f'Caught error', e) + + if isinstance(e, ServiceException): + ex: ServiceException = e + self._logger.error(__name__, ex.get_detailed_message()) + error = ErrorDTO(ex.error_code, ex.message) + return jsonify(error.to_dict()), 500 + else: + tracking_id = uuid.uuid4() + user_message = f'Tracking Id: {tracking_id}' + self._logger.error(__name__, user_message, e) + error = ErrorDTO(None, user_message) + return jsonify(error.to_dict()), 400 + def before_request(self, *args, **kwargs): self._logger.debug(__name__, f'Received GET @{request.url}') headers = str(request.headers).replace("\n", "\n\t") diff --git a/src/bot_api/exception/__init__.py b/src/bot_api/exception/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/bot_api/exception/service_error_code_enum.py b/src/bot_api/exception/service_error_code_enum.py new file mode 100644 index 0000000000..24da48ed24 --- /dev/null +++ b/src/bot_api/exception/service_error_code_enum.py @@ -0,0 +1,19 @@ +from enum import Enum + + +class ServiceErrorCode(Enum): + + Unknown = 0 + + InvalidDependencies = 1 + InvalidData = 2 + NotFound = 3 + DataAlreadyExists = 4 + UnableToAdd = 5 + UnableToDelete = 6 + + InvalidUser = 7 + + ConnectionFailed = 8 + Timeout = 9 + MailError = 10 diff --git a/src/bot_api/exception/service_exception.py b/src/bot_api/exception/service_exception.py new file mode 100644 index 0000000000..6451ae50ed --- /dev/null +++ b/src/bot_api/exception/service_exception.py @@ -0,0 +1,13 @@ +from bot_api.exception.service_error_code_enum import ServiceErrorCode + + +class ServiceException(Exception): + + def __init__(self, error_code: ServiceErrorCode, message: str, *args): + Exception.__init__(self, *args) + + self.error_code = error_code + self.message = message + + def get_detailed_message(self) -> str: + return f'ServiceException - ErrorCode: {self.error_code} - ErrorMessage: {self.message}' diff --git a/src/bot_api/model/error_dto.py b/src/bot_api/model/error_dto.py new file mode 100644 index 0000000000..b55cc1c508 --- /dev/null +++ b/src/bot_api/model/error_dto.py @@ -0,0 +1,34 @@ +import traceback +from typing import Optional + +from cpl_core.console import Console + +from bot_api.abc.dto_abc import DtoABC +from bot_api.exception.service_error_code_enum import ServiceErrorCode + + +class ErrorDTO(DtoABC): + + def __init__(self, error_code: Optional[ServiceErrorCode], message: str): + DtoABC.__init__(self) + + self._error_code = ServiceErrorCode.Unknown if error_code is None else error_code + self._message = message + + @property + def error_code(self) -> ServiceErrorCode: + return self._error_code + + @property + def message(self) -> str: + return self._message + + def from_dict(self, values: dict): + self._error_code = values['ErrorCode'] + self._message = values['Message'] + + def to_dict(self) -> dict: + return { + 'ErrorCode': int(self._error_code.value), + 'Message': self._message + } diff --git a/src/bot_api/route/route.py b/src/bot_api/route/route.py index fbf1a9f8dc..74fbbc6724 100644 --- a/src/bot_api/route/route.py +++ b/src/bot_api/route/route.py @@ -1,3 +1,6 @@ +from flask_cors import cross_origin + + class Route: registered_routes = {} @@ -5,6 +8,7 @@ class Route: def route(cls, path=None, **kwargs): # simple decorator for class based views def inner(fn): + cross_origin(fn) cls.registered_routes[path] = (fn, kwargs) return fn diff --git a/src/bot_api/service/auth_service.py b/src/bot_api/service/auth_service.py index 472585900b..61b5cca601 100644 --- a/src/bot_api/service/auth_service.py +++ b/src/bot_api/service/auth_service.py @@ -13,6 +13,8 @@ from cpl_translation import TranslatePipe from bot_api.abc.auth_service_abc import AuthServiceABC from bot_api.configuration.authentication_settings import AuthenticationSettings from bot_api.configuration.frontend_settings import FrontendSettings +from bot_api.exception.service_error_code_enum import ServiceErrorCode +from bot_api.exception.service_exception import ServiceException from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria from bot_api.logging.api_logger import ApiLogger from bot_api.model.auth_user_dto import AuthUserDTO @@ -131,7 +133,7 @@ class AuthService(AuthServiceABC): return user except Exception as e: self._logger.error(__name__, f'AuthUser not found', e) - raise Exception(f'User not found {email}') + raise ServiceException(ServiceErrorCode.InvalidData, f'User not found {email}') async def find_auth_user_by_email_async(self, email: str) -> Optional[AuthUser]: user = self._auth_users.find_auth_user_by_email(email) @@ -140,12 +142,12 @@ class AuthService(AuthServiceABC): async def add_auth_user_async(self, user_dto: AuthUserDTO): db_user = self._auth_users.find_auth_user_by_email(user_dto.email) if db_user is not None: - raise Exception('User already exists') + raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists') user_dto.password = self._hash_sha256(user_dto.password) user = AUT.to_db(user_dto) if not self._is_email_valid(user.email): - raise Exception('Invalid E-Mail address') + raise ServiceException(ServiceErrorCode.InvalidData, 'Invalid E-Mail address') try: user.confirmation_id = uuid.uuid4() @@ -155,26 +157,27 @@ class AuthService(AuthServiceABC): self._logger.info(__name__, f'Added auth user with E-Mail: {user_dto.email}') except Exception as e: self._logger.error(__name__, f'Cannot add user with E-Mal {user_dto.email}', e) + raise ServiceException(ServiceErrorCode.UnableToAdd, "Invalid E-Mail") async def update_user_async(self, update_user_dto: UpdateAuthUserDTO): if update_user_dto is None: - raise Exception(f'User is empty') + raise ServiceException(ServiceErrorCode.InvalidData, f'User is empty') if update_user_dto.auth_user is None: - raise Exception(f'Existing user is empty') + raise ServiceException(ServiceErrorCode.InvalidData, f'Existing user is empty') if update_user_dto.new_auth_user is None: - raise Exception(f'New user is empty') + raise ServiceException(ServiceErrorCode.InvalidData, f'New user is empty') if not self._is_email_valid(update_user_dto.auth_user.email) or not self._is_email_valid(update_user_dto.new_auth_user.email): - raise Exception(f'Invalid E-Mail') + raise ServiceException(ServiceErrorCode.InvalidData, f'Invalid E-Mail') user = self._auth_users.find_auth_user_by_email(update_user_dto.auth_user.email) if user is None: - raise Exception('User not found') + raise ServiceException(ServiceErrorCode.InvalidUser, 'User not found') if user.confirmation_id is not None: - raise Exception('E-Mail not confirmed') + raise ServiceException(ServiceErrorCode.InvalidUser, 'E-Mail not confirmed') # update first name if update_user_dto.new_auth_user.first_name is not None and update_user_dto.auth_user.first_name != update_user_dto.new_auth_user.first_name: @@ -189,7 +192,7 @@ class AuthService(AuthServiceABC): if update_user_dto.new_auth_user.email is not None and update_user_dto.new_auth_user.email != '' and update_user_dto.auth_user.email != update_user_dto.new_auth_user.email: user_by_new_e_mail = self._auth_users.find_auth_user_by_email(update_user_dto.new_auth_user.email) if user_by_new_e_mail is not None: - raise Exception('User already exists') + raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists') user.email = update_user_dto.new_auth_user.email is_existing_password_set = False @@ -200,7 +203,7 @@ class AuthService(AuthServiceABC): update_user_dto.auth_user.Password = self._hash_sha256(update_user_dto.auth_user.Password) if update_user_dto.auth_user.Password != user.Password: - raise Exception('Wrong password') + raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong password') if update_user_dto.new_auth_user.Password is not None and update_user_dto.new_auth_user.Password != '': is_new_password_set = True @@ -214,27 +217,27 @@ class AuthService(AuthServiceABC): async def update_user_as_admin_async(self, update_user_dto: UpdateAuthUserDTO): if update_user_dto is None: - raise Exception(f'User is empty') + raise ServiceException(ServiceErrorCode.InvalidData, f'User is empty') if update_user_dto.auth_user is None: - raise Exception(f'Existing user is empty') + raise ServiceException(ServiceErrorCode.InvalidData, f'Existing user is empty') if update_user_dto.new_auth_user is None: - raise Exception(f'New user is empty') + raise ServiceException(ServiceErrorCode.InvalidData, f'New user is empty') if not self._is_email_valid(update_user_dto.auth_user.email) or not self._is_email_valid(update_user_dto.new_auth_user.email): - raise Exception(f'Invalid E-Mail') + raise ServiceException(ServiceErrorCode.InvalidData, f'Invalid E-Mail') user = self._auth_users.find_auth_user_by_email(update_user_dto.auth_user.email) if user is None: - raise Exception('User not found') + raise ServiceException(ServiceErrorCode.InvalidUser, 'User not found') if user.ConfirmationId is not None and update_user_dto.new_auth_user.is_confirmed: user.ConfirmationId = None elif user.ConfirmationId is None and not update_user_dto.new_auth_user.is_confirmed: user.confirmation_id = uuid.uuid4() # else - # raise Exception(ServiceErrorCode.InvalidUser, 'E-Mail not confirmed') + # raise ServiceException(ServiceErrorCode.InvalidUser, 'E-Mail not confirmed') # update first name if update_user_dto.new_auth_user.first_name is not None and update_user_dto.auth_user.first_name != update_user_dto.new_auth_user.first_name: @@ -248,7 +251,7 @@ class AuthService(AuthServiceABC): if update_user_dto.new_auth_user.email is not None and update_user_dto.new_auth_user.email != '' and update_user_dto.auth_user.email != update_user_dto.new_auth_user.email: user_by_new_e_mail = self._auth_users.find_auth_user_by_email(update_user_dto.new_auth_user.email) if user_by_new_e_mail is not None: - raise Exception('User already exists') + raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists') user.EMail = update_user_dto.new_auth_user.email # update password @@ -268,7 +271,7 @@ class AuthService(AuthServiceABC): self._db.save_changes() except Exception as e: self._logger.error(__name__, f'Cannot delete user', e) - raise Exception(f'Cannot delete user by mail {email}') + raise ServiceException(ServiceErrorCode.UnableToDelete, f'Cannot delete user by mail {email}') async def delete_auth_user_async(self, user_dto: AuthUserDTO): try: @@ -276,21 +279,21 @@ class AuthService(AuthServiceABC): self._db.save_changes() except Exception as e: self._logger.error(__name__, f'Cannot delete user', e) - raise Exception(f'Cannot delete user by mail {user_dto.email}') + raise ServiceException(ServiceErrorCode.UnableToDelete, f'Cannot delete user by mail {user_dto.email}') async def login_async(self, user_dto: AuthUserDTO) -> TokenDTO: if user_dto is None: - raise Exception('User not set') + raise ServiceException(ServiceErrorCode.InvalidData, 'User not set') db_user = self._auth_users.find_auth_user_by_email(user_dto.email) if db_user is None: - raise Exception(f'User with E-Mail {user_dto.email} not found') + raise ServiceException(ServiceErrorCode.InvalidUser, f'User not found') user_dto.password = self._hash_sha256(user_dto.password) if db_user.password != user_dto.password: - raise Exception('Wrong password') + raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong password') - token = self._generate_token(user_dto) + token = self._generate_token(db_user) refresh_token = self._create_and_save_refresh_token(db_user) if db_user.forgot_password_id is not None: db_user.forgot_password_id = None @@ -300,16 +303,16 @@ class AuthService(AuthServiceABC): async def refresh_async(self, token_dto: TokenDTO) -> TokenDTO: if token_dto is None: - raise Exception(f'Token not set') + raise ServiceException(ServiceErrorCode.InvalidData, f'Token not set') token = jwt.decode(token_dto.token, key=self._auth_settings.secret_key) if token is None or 'email' not in token: - raise Exception('Token invalid') + raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid') try: user = self._auth_users.get_auth_user_by_email(token) if user is None or user.refresh_token != token_dto.refresh_token or user.refresh_token_expire_time <= datetime.now(): - raise Exception('Token expired') + raise ServiceException(ServiceErrorCode.InvalidData, 'Token expired') return TokenDTO(self._generate_token(user), self._create_and_save_refresh_token(user)) except Exception as e: @@ -318,13 +321,13 @@ class AuthService(AuthServiceABC): async def revoke_async(self, token_dto: TokenDTO): if token_dto is None or token_dto.token is None or token_dto.refresh_token is None: - raise Exception('Token not set') + raise ServiceException(ServiceErrorCode.InvalidData, 'Token not set') token = jwt.decode(token_dto.token, key=self._auth_settings.secret_key) try: user = self._auth_users.get_auth_user_by_email(token) if user is None or user.refresh_token != token_dto.refresh_token or user.refresh_token_expire_time <= datetime.now(): - raise Exception('Token expired') + raise ServiceException(ServiceErrorCode.InvalidData, 'Token expired') user.refresh_token = None self._auth_users.update_auth_user(user) @@ -359,13 +362,13 @@ class AuthService(AuthServiceABC): async def reset_password_async(self, rp_dto: ResetPasswordDTO): user = self._auth_users.find_auth_user_by_forgot_password_id(rp_dto.id) if user is None: - raise Exception(f'User by forgot password id {rp_dto.id} not found') + raise ServiceException(ServiceErrorCode.InvalidUser, f'User by forgot password id {rp_dto.id} not found') if user.confirmation_id is not None: - raise Exception(f'E-Mail not confirmed') + raise ServiceException(ServiceErrorCode.InvalidUser, f'E-Mail not confirmed') if user.password is None or rp_dto.password == '': - raise Exception(f'Password not set') + raise ServiceException(ServiceErrorCode.InvalidData, f'Password not set') user.password = self._hash_sha256(rp_dto.password) self._db.save_changes() diff --git a/src/bot_data/migration/api_migration.py b/src/bot_data/migration/api_migration.py index 187dc5fcbe..61f9d15615 100644 --- a/src/bot_data/migration/api_migration.py +++ b/src/bot_data/migration/api_migration.py @@ -27,9 +27,9 @@ class ApiMigration(MigrationABC): `ConfirmationId` varchar(255) DEFAULT NULL, `ForgotPasswordId` varchar(255) DEFAULT NULL, `RefreshTokenExpiryTime` datetime(6) NOT NULL, - `AuthRole` int NOT NULL DEFAULT '0' + `AuthRole` int NOT NULL DEFAULT '0', `CreatedOn` datetime(6) NOT NULL, - `LastModifiedOn` datetime(6) NOT NULL, + `LastModifiedOn` datetime(6) NOT NULL ) """) ) diff --git a/src/bot_data/model/auth_user.py b/src/bot_data/model/auth_user.py index eeb90d76e0..57cdde0aeb 100644 --- a/src/bot_data/model/auth_user.py +++ b/src/bot_data/model/auth_user.py @@ -132,21 +132,21 @@ class AuthUser(TableABC): def get_select_by_email_string(email: str) -> str: return str(f""" SELECT * FROM `AuthUsers` - WHERE `EMail` = {email}; + WHERE `EMail` = '{email}'; """) @staticmethod def get_select_by_confirmation_id_string(id: str) -> str: return str(f""" SELECT * FROM `AuthUsers` - WHERE `ConfirmationId` = {id}; + WHERE `ConfirmationId` = '{id}'; """) @staticmethod def get_select_by_forgot_password_i_string(id: str) -> str: return str(f""" SELECT * FROM `AuthUsers` - WHERE `ForgotPasswordId` = {id}; + WHERE `ForgotPasswordId` = '{id}'; """) @property @@ -167,17 +167,17 @@ class AuthUser(TableABC): `LastModifiedOn` ) VALUES ( {self._auth_user_id}, - {self._first_name}, - {self._last_name}, - {self._email}, - {self._password}, - {self._refresh_token}, - {self._confirmation_id}, - {self._forgot_password_id}, - {self._refresh_token_expire_time}, - {self._auth_role_id.value} - {self._created_at}, - {self._modified_at} + '{self._first_name}', + '{self._last_name}', + '{self._email}', + '{self._password}', + '{self._refresh_token}', + '{self._confirmation_id}', + '{self._forgot_password_id}', + '{self._refresh_token_expire_time}', + {self._auth_role_id.value}, + '{self._created_at}', + '{self._modified_at}' ) """) From 5cd91d8341660045bb8b707a95a24a7f70eae09c Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 15 Oct 2022 09:32:41 +0200 Subject: [PATCH 013/102] Fixed error and dto handling #70 --- src/bot_api/model/auth_user_dto.py | 28 +++++------ .../model/auth_user_filtered_result_dto.py | 8 ++-- src/bot_api/model/email_string_dto.py | 4 +- src/bot_api/model/error_dto.py | 4 +- src/bot_api/model/reset_password_dto.py | 8 ++-- src/bot_api/model/settings_dto.py | 48 +++++++++---------- src/bot_api/model/token_dto.py | 8 ++-- src/bot_api/model/update_auth_user_dto.py | 12 ++--- src/bot_api/model/version_dto.py | 12 ++--- 9 files changed, 66 insertions(+), 66 deletions(-) diff --git a/src/bot_api/model/auth_user_dto.py b/src/bot_api/model/auth_user_dto.py index 304ce047e0..1992389053 100644 --- a/src/bot_api/model/auth_user_dto.py +++ b/src/bot_api/model/auth_user_dto.py @@ -82,21 +82,21 @@ class AuthUserDTO(DtoABC): self.auth_role = value def from_dict(self, values: dict): - self._id = values['Id'] - self._first_name = values['FirstName'] - self._last_name = values['LastName'] - self._email = values['EMail'] - self._password = values['Password'] - self._is_confirmed = values['IsConfirmed'] - self._auth_role = values['AuthRole'] + self._id = values['id'] + self._first_name = values['firstName'] + self._last_name = values['lastName'] + self._email = values['email'] + self._password = values['password'] + self._is_confirmed = values['isConfirmed'] + self._auth_role = values['authRole'] def to_dict(self) -> dict: return { - "Id": self._id, - "FirstName": self._first_name, - "LastName": self._last_name, - "EMail": self._email, - "Password": self._password, - "IsConfirmed": self._is_confirmed, - "AuthRole": self._auth_role, + 'id': self._id, + 'firstName': self._first_name, + 'lastName': self._last_name, + 'email': self._email, + 'password': self._password, + 'isConfirmed': self._is_confirmed, + 'authRole': self._auth_role, } diff --git a/src/bot_api/model/auth_user_filtered_result_dto.py b/src/bot_api/model/auth_user_filtered_result_dto.py index 6edbdb4462..a3125d25e5 100644 --- a/src/bot_api/model/auth_user_filtered_result_dto.py +++ b/src/bot_api/model/auth_user_filtered_result_dto.py @@ -11,11 +11,11 @@ class AuthUserFilteredResultDTO(DtoABC, FilteredResult): FilteredResult.__init__(self, result, total_count) def from_dict(self, values: dict): - self._result = values['Users'] - self._total_count = values['TotalCount'] + self._result = values['users'] + self._total_count = values['totalCount'] def to_dict(self) -> dict: return { - 'Users': self.result, - 'TotalCount': self.total_count + 'users': self.result, + 'totalCount': self.total_count } diff --git a/src/bot_api/model/email_string_dto.py b/src/bot_api/model/email_string_dto.py index 1f5ef08738..5ad6eecb8d 100644 --- a/src/bot_api/model/email_string_dto.py +++ b/src/bot_api/model/email_string_dto.py @@ -13,9 +13,9 @@ class EMailStringDTO(DtoABC): self._email = email def from_dict(self, values: dict): - self._email = values['EMail'] + self._email = values['email'] def to_dict(self) -> dict: return { - 'EMail': self._email + 'email': self._email } diff --git a/src/bot_api/model/error_dto.py b/src/bot_api/model/error_dto.py index b55cc1c508..39c7d6a114 100644 --- a/src/bot_api/model/error_dto.py +++ b/src/bot_api/model/error_dto.py @@ -29,6 +29,6 @@ class ErrorDTO(DtoABC): def to_dict(self) -> dict: return { - 'ErrorCode': int(self._error_code.value), - 'Message': self._message + 'errorCode': int(self._error_code.value), + 'message': self._message } diff --git a/src/bot_api/model/reset_password_dto.py b/src/bot_api/model/reset_password_dto.py index 0bacce596e..64de816d37 100644 --- a/src/bot_api/model/reset_password_dto.py +++ b/src/bot_api/model/reset_password_dto.py @@ -22,11 +22,11 @@ class ResetPasswordDTO(DtoABC): return self._password def from_dict(self, values: dict): - self._id = values['Id'] - self._password = values['Password'] + self._id = values['id'] + self._password = values['password'] def to_dict(self) -> dict: return { - 'Id': self._id, - 'Password': self._password + 'id': self._id, + 'password': self._password } diff --git a/src/bot_api/model/settings_dto.py b/src/bot_api/model/settings_dto.py index ce3ec436cc..567f393126 100644 --- a/src/bot_api/model/settings_dto.py +++ b/src/bot_api/model/settings_dto.py @@ -37,31 +37,31 @@ class SettingsDTO(DtoABC): self._mail_transceiver_address = mail_transceiver_address def from_dict(self, values: dict): - self._web_version = values['WebVersion'] - self._api_version.from_dict(values['ApiVersion']) - self._config_path = values['ConfigPath'] - self._web_base_url = values['WebBaseURL'] - self._api_base_url = values['ApiBaseURL'] - self._token_expire_time = values['TokenExpireTime'] - self._refresh_token_expire_time = values['RefreshTokenExpireTime'] - self._mail_user = values['MailUser'] - self._mail_port = values['MailPort'] - self._mail_host = values['MailHost'] - self._mail_transceiver = values['MailTransceiver'] - self._mail_transceiver_address = values['MailTransceiverAddress'] + self._web_version = values['webVersion'] + self._api_version.from_dict(values['apiVersion']) + self._config_path = values['configPath'] + self._web_base_url = values['webBaseURL'] + self._api_base_url = values['apiBaseURL'] + self._token_expire_time = values['tokenExpireTime'] + self._refresh_token_expire_time = values['refreshTokenExpireTime'] + self._mail_user = values['mailUser'] + self._mail_port = values['mailPort'] + self._mail_host = values['mailHost'] + self._mail_transceiver = values['mailTransceiver'] + self._mail_transceiver_address = values['mailTransceiverAddress'] def to_dict(self) -> dict: return { - 'WebVersion': self._web_version, - 'ApiVersion': self._api_version.to_dict(), - 'ConfigPath': self._config_path, - 'WebBaseURL': self._web_base_url, - 'ApiBaseURL': self._api_base_url, - 'TokenExpireTime': self._token_expire_time, - 'RefreshTokenExpireTime': self._refresh_token_expire_time, - 'MailUser': self._mail_user, - 'MailPort': self._mail_port, - 'MailHost': self._mail_host, - 'MailTransceiver': self._mail_transceiver, - 'MailTransceiverAddress': self._mail_transceiver_address, + 'webVersion': self._web_version, + 'apiVersion': self._api_version.to_dict(), + 'configPath': self._config_path, + 'webBaseURL': self._web_base_url, + 'apiBaseURL': self._api_base_url, + 'tokenExpireTime': self._token_expire_time, + 'refreshTokenExpireTime': self._refresh_token_expire_time, + 'mailUser': self._mail_user, + 'mailPort': self._mail_port, + 'mailHost': self._mail_host, + 'mailTransceiver': self._mail_transceiver, + 'mailTransceiverAddress': self._mail_transceiver_address, } diff --git a/src/bot_api/model/token_dto.py b/src/bot_api/model/token_dto.py index 987d9ad296..d5fc308780 100644 --- a/src/bot_api/model/token_dto.py +++ b/src/bot_api/model/token_dto.py @@ -22,11 +22,11 @@ class TokenDTO(DtoABC): return self._refresh_token def from_dict(self, values: dict): - self._token = values['Token'] - self._refresh_token = values['RefreshToken'] + self._token = values['token'] + self._refresh_token = values['refreshToken'] def to_dict(self) -> dict: return { - 'Token': self._token, - 'RefreshToken': self._refresh_token + 'token': self._token, + 'refreshToken': self._refresh_token } diff --git a/src/bot_api/model/update_auth_user_dto.py b/src/bot_api/model/update_auth_user_dto.py index 7c481330a4..682f0122b4 100644 --- a/src/bot_api/model/update_auth_user_dto.py +++ b/src/bot_api/model/update_auth_user_dto.py @@ -33,13 +33,13 @@ class UpdateAuthUserDTO(DtoABC): return self._change_password def from_dict(self, values: dict): - self._auth_user = values['AuthUser'] - self._new_auth_user = values['NewAuthUser'] - self._change_password = False if 'ChangePassword' not in values else values['ChangePassword'] + self._auth_user = values['authUser'] + self._new_auth_user = values['newAuthUser'] + self._change_password = False if 'changePassword' not in values else values['changePassword'] def to_dict(self) -> dict: return { - 'AuthUser': self._auth_user, - 'NewAuthUser': self._new_auth_user, - 'ChangePassword': self._change_password + 'authUser': self._auth_user, + 'newAuthUser': self._new_auth_user, + 'changePassword': self._change_password } diff --git a/src/bot_api/model/version_dto.py b/src/bot_api/model/version_dto.py index 8ef98dc401..c1504478e9 100644 --- a/src/bot_api/model/version_dto.py +++ b/src/bot_api/model/version_dto.py @@ -15,13 +15,13 @@ class VersionDTO(DtoABC): self._micro = micro def from_dict(self, values: dict): - self._major = values['Major'] - self._minor = values['Minor'] - self._micro = values['Micro'] + self._major = values['major'] + self._minor = values['minor'] + self._micro = values['micro'] def to_dict(self) -> dict: return { - 'Major': self._major, - 'Minor': self._minor, - 'Micro': self._micro, + 'major': self._major, + 'minor': self._minor, + 'micro': self._micro, } From 119f4e9d04f5a4d8efcad96879a94d09f956210c Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 15 Oct 2022 12:54:10 +0200 Subject: [PATCH 014/102] Improved api #70 --- src/bot/application.py | 2 +- src/bot/bot.json | 2 +- src/bot/translation/de.json | 2 +- src/bot_api/abc/auth_service_abc.py | 7 ++-- src/bot_api/api_module.py | 4 +- .../config/apisettings.edrafts-lapi.json | 2 +- src/bot_api/controller/auth_controller.py | 10 +++-- .../{api_controller.py => gui_controller.py} | 9 ++-- .../filter/auth_user_select_criteria.py | 2 +- src/bot_api/model/auth_user_dto.py | 13 +++--- src/bot_api/service/auth_service.py | 42 ++++++++++++------- .../transformer/auth_user_transformer.py | 13 +++--- src/bot_data/migration/api_migration.py | 25 +++++------ src/bot_data/model/auth_role_enum.py | 4 +- src/bot_data/model/auth_user.py | 20 ++++----- .../service/auth_user_repository_service.py | 39 +++++++++-------- 16 files changed, 108 insertions(+), 88 deletions(-) rename src/bot_api/controller/{api_controller.py => gui_controller.py} (92%) diff --git a/src/bot/application.py b/src/bot/application.py index 726cdbdbf0..6c65a6b49c 100644 --- a/src/bot/application.py +++ b/src/bot/application.py @@ -46,7 +46,7 @@ class Application(DiscordBotApplicationABC): if self._feature_flags.get_flag(FeatureFlagsEnum.api_module): self._api.start() - if self._feature_flags.get_flag(FeatureFlagsEnum.api_only): + if self._feature_flags.get_flag(FeatureFlagsEnum.api_only) and self._environment.environment_name == 'development': self._api.join() return diff --git a/src/bot/bot.json b/src/bot/bot.json index 64495674d9..df826bb7ef 100644 --- a/src/bot/bot.json +++ b/src/bot/bot.json @@ -18,7 +18,7 @@ "Dependencies": [ "cpl-core==2022.10.0.post6", "cpl-translation==2022.10.0.post1", - "cpl-query==2022.10.0", + "cpl-query==2022.10.0.post1", "cpl-discord==2022.10.0.post5" ], "DevDependencies": [ diff --git a/src/bot/translation/de.json b/src/bot/translation/de.json index 5ffe9dcf36..7850782ca2 100644 --- a/src/bot/translation/de.json +++ b/src/bot/translation/de.json @@ -163,7 +163,7 @@ "auth": { "confirmation": { "subject": "E-Mail für {} {} bestätigen", - "message": "Öffne den Link um die E-Mail zu bestätigen:\n{}auth/forgot-password/{}" + "message": "Öffne den Link um die E-Mail zu bestätigen:\n{}auth/register/{}" }, "forgot_password": { "subject": "Passwort für {} {} zurücksetzen", diff --git a/src/bot_api/abc/auth_service_abc.py b/src/bot_api/abc/auth_service_abc.py index e4f611c69f..28d1374911 100644 --- a/src/bot_api/abc/auth_service_abc.py +++ b/src/bot_api/abc/auth_service_abc.py @@ -9,7 +9,6 @@ from bot_api.model.email_string_dto import EMailStringDTO from bot_api.model.reset_password_dto import ResetPasswordDTO from bot_api.model.token_dto import TokenDTO from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO -from bot_data.model.auth_user import AuthUser class AuthServiceABC(ABC): @@ -18,16 +17,16 @@ class AuthServiceABC(ABC): def __init__(self): pass @abstractmethod - async def get_all_auth_users_async(self) -> List[AuthUser]: pass + async def get_all_auth_users_async(self) -> List[AuthUserDTO]: pass @abstractmethod async def get_filtered_auth_users_async(self, criteria: AuthUserSelectCriteria) -> AuthUserFilteredResultDTO: pass @abstractmethod - async def get_auth_user_by_email_async(self, email: str) -> AuthUser: pass + async def get_auth_user_by_email_async(self, email: str) -> AuthUserDTO: pass @abstractmethod - async def find_auth_user_by_email_async(self, email: str) -> AuthUser: pass + async def find_auth_user_by_email_async(self, email: str) -> AuthUserDTO: pass @abstractmethod async def add_auth_user_async(self, user_dto: AuthUserDTO) -> int: pass diff --git a/src/bot_api/api_module.py b/src/bot_api/api_module.py index ff1be35b2e..6474a3e522 100644 --- a/src/bot_api/api_module.py +++ b/src/bot_api/api_module.py @@ -10,7 +10,7 @@ from flask import Flask from bot_api.abc.auth_service_abc import AuthServiceABC from bot_api.api import Api from bot_api.api_thread import ApiThread -from bot_api.controller.api_controller import ApiController +from bot_api.controller.gui_controller import GuiController from bot_api.controller.auth_controller import AuthController from bot_api.service.auth_service import AuthService from bot_core.abc.module_abc import ModuleABC @@ -38,4 +38,4 @@ class ApiModule(ModuleABC): services.add_transient(AuthServiceABC, AuthService) services.add_transient(AuthController) - services.add_transient(ApiController) + services.add_transient(GuiController) diff --git a/src/bot_api/config/apisettings.edrafts-lapi.json b/src/bot_api/config/apisettings.edrafts-lapi.json index fb7c257c3b..d71694b228 100644 --- a/src/bot_api/config/apisettings.edrafts-lapi.json +++ b/src/bot_api/config/apisettings.edrafts-lapi.json @@ -7,7 +7,7 @@ "Authentication": { "SecretKey": "F3b5LDz+#Jvzg=W!@gsa%xsF", "Issuer": "http://localhost:5000", - "Audience": "http://localhost:5000", + "Audience": "http://localhost:4200", "TokenExpireTime": 1, "RefreshTokenExpireTime": 7 }, diff --git a/src/bot_api/controller/auth_controller.py b/src/bot_api/controller/auth_controller.py index adb6f3a249..c5e10d1c6c 100644 --- a/src/bot_api/controller/auth_controller.py +++ b/src/bot_api/controller/auth_controller.py @@ -40,21 +40,25 @@ class AuthController: @Route.get(f'{BasePath}/users') async def get_all_users(self) -> Response: - return jsonify(await self._auth_service.get_all_auth_users_async()) + result = await self._auth_service.get_all_auth_users_async() + return jsonify(result.select(lambda x: x.to_dict())) @Route.post(f'{BasePath}/users/get/filtered') async def get_filtered_users(self) -> Response: dto: AuthUserSelectCriteria = JSONProcessor.process(AuthUserSelectCriteria, request.get_json(force=True, silent=True)) result = await self._auth_service.get_filtered_auth_users_async(dto) + result.result = result.result.select(lambda x: x.to_dict()) return jsonify(result.to_dict()) @Route.get(f'{BasePath}/users/get/') async def get_user_from_email(self, email: str) -> Response: - return jsonify(await self._auth_service.get_auth_user_by_email_async(email)) + result = await self._auth_service.get_auth_user_by_email_async(email) + return jsonify(result.to_dict()) @Route.get(f'{BasePath}/users/find/') async def find_user_from_email(self, email: str) -> Response: - return jsonify(await self._auth_service.find_auth_user_by_email_async(email)) + result = await self._auth_service.find_auth_user_by_email_async(email) + return jsonify(result.to_dict()) @Route.post(f'{BasePath}/register') async def register(self): diff --git a/src/bot_api/controller/api_controller.py b/src/bot_api/controller/gui_controller.py similarity index 92% rename from src/bot_api/controller/api_controller.py rename to src/bot_api/controller/gui_controller.py index 1b7ae669d2..a2fa883aab 100644 --- a/src/bot_api/controller/api_controller.py +++ b/src/bot_api/controller/gui_controller.py @@ -12,7 +12,8 @@ from bot_api.model.version_dto import VersionDTO from bot_api.route.route import Route -class ApiController: +class GuiController: + BasePath = f'/api/gui' def __init__( self, @@ -32,13 +33,13 @@ class ApiController: self._mail_settings = mail_settings self._mailer = mailer - @Route.route('/api/api-version') + @Route.get(f'{BasePath}/api-version') async def api_version(self): import bot_api version = bot_api.version_info return VersionDTO(version.major, version.minor, version.micro).to_dict() - @Route.route('/api/settings') + @Route.get(f'{BasePath}/settings') async def settings(self): # TODO: Authentication import bot_api @@ -59,7 +60,7 @@ class ApiController: self._mail_settings.user_name, ).to_dict() - @Route.route('/api/send-test-mail/') + @Route.get(f'{BasePath}/send-test-mail/') async def send_test_mail(self, email: str): # TODO: Authentication mail = EMail() diff --git a/src/bot_api/filter/auth_user_select_criteria.py b/src/bot_api/filter/auth_user_select_criteria.py index 497f5eaa18..8ac7784e10 100644 --- a/src/bot_api/filter/auth_user_select_criteria.py +++ b/src/bot_api/filter/auth_user_select_criteria.py @@ -13,7 +13,7 @@ class AuthUserSelectCriteria(SelectCriteriaABC): first_name: str, last_name: str, email: str, - auth_role=0 + auth_role: int ): SelectCriteriaABC.__init__(self, page_index, page_size, sort_direction, sort_column) diff --git a/src/bot_api/model/auth_user_dto.py b/src/bot_api/model/auth_user_dto.py index 1992389053..4fb5339455 100644 --- a/src/bot_api/model/auth_user_dto.py +++ b/src/bot_api/model/auth_user_dto.py @@ -1,8 +1,5 @@ -import traceback from typing import Optional -from cpl_core.console import Console - from bot_api.abc.dto_abc import DtoABC from bot_data.model.auth_role_enum import AuthRoleEnum @@ -14,7 +11,7 @@ class AuthUserDTO(DtoABC): id: int, first_name: str, last_name: str, - e_mail: str, + email: str, password: str, confirmation_id: Optional[str], auth_role: AuthRoleEnum, @@ -24,7 +21,7 @@ class AuthUserDTO(DtoABC): self._id = id self._first_name = first_name self._last_name = last_name - self._email = e_mail + self._email = email self._password = password self._is_confirmed = confirmation_id is None self._auth_role = auth_role @@ -75,11 +72,11 @@ class AuthUserDTO(DtoABC): @property def auth_role(self) -> AuthRoleEnum: - return self.auth_role + return self._auth_role @auth_role.setter def auth_role(self, value: AuthRoleEnum): - self.auth_role = value + self._auth_role = value def from_dict(self, values: dict): self._id = values['id'] @@ -98,5 +95,5 @@ class AuthUserDTO(DtoABC): 'email': self._email, 'password': self._password, 'isConfirmed': self._is_confirmed, - 'authRole': self._auth_role, + 'authRole': self._auth_role.value, } diff --git a/src/bot_api/service/auth_service.py b/src/bot_api/service/auth_service.py index 61b5cca601..07e750284c 100644 --- a/src/bot_api/service/auth_service.py +++ b/src/bot_api/service/auth_service.py @@ -65,24 +65,35 @@ class AuthService(AuthServiceABC): @staticmethod def _is_email_valid(email: str) -> bool: - regex = '^[a-z0-9]+[\\._]?[a-z0-9]+[@]\\w+[.]\\w{2,3}$' - return bool(re.search(regex, email)) + if re.match(re.compile(r'^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$'), email) is not None: + return True + + return False def _generate_token(self, user: AuthUser) -> str: token = jwt.encode( payload={ 'user_id': user.id, 'email': user.email, - 'role': user.auth_role, + 'role': user.auth_role.value, 'exp': datetime.now(tz=timezone.utc) + timedelta(days=self._auth_settings.token_expire_time), 'iss': self._auth_settings.issuer, 'aud': self._auth_settings.audience }, - key=self._auth_settings.secret_key, + key=self._auth_settings.secret_key ) return token + def _decode_token(self, token: str) -> dict: + return jwt.decode( + token, + key=self._auth_settings.secret_key, + issuer=self._auth_settings.issuer, + audience=self._auth_settings.audience, + algorithms=['HS256'] + ) + def _create_and_save_refresh_token(self, user: AuthUser) -> str: token = str(uuid.uuid4()) user.refresh_token = token @@ -113,7 +124,7 @@ class AuthService(AuthServiceABC): mail.body = self._t.transform('api.auth.forgot_password.message').format(url, user.forgot_password_id) self._mailer.send_mail(mail) - async def get_all_auth_users_async(self) -> List[AuthUser]: + async def get_all_auth_users_async(self) -> List[AuthUserDTO]: result = self._auth_users.get_all_auth_users() \ .select(lambda x: AUT.to_dto(x)) return List(AuthUserDTO, result) @@ -127,10 +138,9 @@ class AuthService(AuthServiceABC): users.total_count ) - async def get_auth_user_by_email_async(self, email: str) -> AuthUser: + async def get_auth_user_by_email_async(self, email: str) -> AuthUserDTO: try: - user = self._auth_users.get_auth_user_by_email(email) - return user + return AUT.to_dto(self._auth_users.get_auth_user_by_email(email)) except Exception as e: self._logger.error(__name__, f'AuthUser not found', e) raise ServiceException(ServiceErrorCode.InvalidData, f'User not found {email}') @@ -139,7 +149,7 @@ class AuthService(AuthServiceABC): user = self._auth_users.find_auth_user_by_email(email) return AUT.to_dto(user) if user is not None else None - async def add_auth_user_async(self, user_dto: AuthUserDTO): + async def add_auth_user_async(self, user_dto: AuthUser): db_user = self._auth_users.find_auth_user_by_email(user_dto.email) if db_user is not None: raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists') @@ -151,7 +161,7 @@ class AuthService(AuthServiceABC): try: user.confirmation_id = uuid.uuid4() - self._auth_users.update_auth_user(user) + self._auth_users.add_auth_user(user) self._send_confirmation_id_to_user(user) self._db.save_changes() self._logger.info(__name__, f'Added auth user with E-Mail: {user_dto.email}') @@ -273,7 +283,7 @@ class AuthService(AuthServiceABC): self._logger.error(__name__, f'Cannot delete user', e) raise ServiceException(ServiceErrorCode.UnableToDelete, f'Cannot delete user by mail {email}') - async def delete_auth_user_async(self, user_dto: AuthUserDTO): + async def delete_auth_user_async(self, user_dto: AuthUser): try: self._auth_users.delete_auth_user(AUT.to_db(user_dto)) self._db.save_changes() @@ -281,7 +291,7 @@ class AuthService(AuthServiceABC): self._logger.error(__name__, f'Cannot delete user', e) raise ServiceException(ServiceErrorCode.UnableToDelete, f'Cannot delete user by mail {user_dto.email}') - async def login_async(self, user_dto: AuthUserDTO) -> TokenDTO: + async def login_async(self, user_dto: AuthUser) -> TokenDTO: if user_dto is None: raise ServiceException(ServiceErrorCode.InvalidData, 'User not set') @@ -305,12 +315,12 @@ class AuthService(AuthServiceABC): if token_dto is None: raise ServiceException(ServiceErrorCode.InvalidData, f'Token not set') - token = jwt.decode(token_dto.token, key=self._auth_settings.secret_key) + token = self._decode_token(token_dto.token) if token is None or 'email' not in token: raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid') try: - user = self._auth_users.get_auth_user_by_email(token) + user = self._auth_users.get_auth_user_by_email(token['email']) if user is None or user.refresh_token != token_dto.refresh_token or user.refresh_token_expire_time <= datetime.now(): raise ServiceException(ServiceErrorCode.InvalidData, 'Token expired') @@ -323,9 +333,9 @@ class AuthService(AuthServiceABC): if token_dto is None or token_dto.token is None or token_dto.refresh_token is None: raise ServiceException(ServiceErrorCode.InvalidData, 'Token not set') - token = jwt.decode(token_dto.token, key=self._auth_settings.secret_key) + token = self._decode_token(token_dto.token) try: - user = self._auth_users.get_auth_user_by_email(token) + user = self._auth_users.get_auth_user_by_email(token['email']) if user is None or user.refresh_token != token_dto.refresh_token or user.refresh_token_expire_time <= datetime.now(): raise ServiceException(ServiceErrorCode.InvalidData, 'Token expired') diff --git a/src/bot_api/transformer/auth_user_transformer.py b/src/bot_api/transformer/auth_user_transformer.py index 50258b016e..b324445b6b 100644 --- a/src/bot_api/transformer/auth_user_transformer.py +++ b/src/bot_api/transformer/auth_user_transformer.py @@ -1,12 +1,15 @@ +from datetime import datetime, timezone + from bot_api.abc.auth_user_transformer_abc import AuthUserTransformerABC from bot_api.model.auth_user_dto import AuthUserDTO +from bot_data.model.auth_role_enum import AuthRoleEnum from bot_data.model.auth_user import AuthUser class AuthUserTransformer(AuthUserTransformerABC): @staticmethod - def to_db(dto: AuthUserDTO) -> AuthUser: + def to_db(dto: AuthUser) -> AuthUser: return AuthUser( dto.first_name, dto.last_name, @@ -15,9 +18,9 @@ class AuthUserTransformer(AuthUserTransformerABC): None, None, None, - None, - dto.auth_role, - id=dto.id + datetime.now(tz=timezone.utc), + AuthRoleEnum.normal if dto.auth_role is None else dto.auth_role, + id=0 if dto.id is None else dto.id ) @staticmethod @@ -28,6 +31,6 @@ class AuthUserTransformer(AuthUserTransformerABC): db.last_name, db.email, db.password, - db.confirmation_id is None, + db.confirmation_id, db.auth_role ) diff --git a/src/bot_data/migration/api_migration.py b/src/bot_data/migration/api_migration.py index 61f9d15615..80754c88a5 100644 --- a/src/bot_data/migration/api_migration.py +++ b/src/bot_data/migration/api_migration.py @@ -18,18 +18,19 @@ class ApiMigration(MigrationABC): self._cursor.execute( str(f""" CREATE TABLE IF NOT EXISTS `AuthUsers` ( - `Id` bigint NOT NULL, - `FirstName` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, - `LastName` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, - `EMail` varchar(255) DEFAULT NULL, - `Password` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, - `RefreshToken` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, - `ConfirmationId` varchar(255) DEFAULT NULL, - `ForgotPasswordId` varchar(255) DEFAULT NULL, - `RefreshTokenExpiryTime` datetime(6) NOT NULL, - `AuthRole` int NOT NULL DEFAULT '0', - `CreatedOn` datetime(6) NOT NULL, - `LastModifiedOn` datetime(6) NOT NULL + `Id` BIGINT NOT NULL AUTO_INCREMENT, + `FirstName` VARCHAR(255), + `LastName` VARCHAR(255), + `EMail` VARCHAR(255), + `Password` VARCHAR(255), + `RefreshToken` VARCHAR(255), + `ConfirmationId` VARCHAR(255) DEFAULT NULL, + `ForgotPasswordId` VARCHAR(255) DEFAULT NULL, + `RefreshTokenExpiryTime` DATETIME(6) NOT NULL, + `AuthRole` INT NOT NULL DEFAULT '0', + `CreatedOn` DATETIME(6) NOT NULL, + `LastModifiedOn` DATETIME(6) NOT NULL, + PRIMARY KEY(`Id`) ) """) ) diff --git a/src/bot_data/model/auth_role_enum.py b/src/bot_data/model/auth_role_enum.py index 8b03232577..e152613670 100644 --- a/src/bot_data/model/auth_role_enum.py +++ b/src/bot_data/model/auth_role_enum.py @@ -3,5 +3,5 @@ from enum import Enum class AuthRoleEnum(Enum): - Normal = 0 - Admin = 1 + normal = 0 + admin = 1 diff --git a/src/bot_data/model/auth_user.py b/src/bot_data/model/auth_user.py index 57cdde0aeb..26ba09a868 100644 --- a/src/bot_data/model/auth_user.py +++ b/src/bot_data/model/auth_user.py @@ -17,7 +17,7 @@ class AuthUser(TableABC): refresh_token: Optional[str], confirmation_id: Optional[str], forgot_password_id: Optional[str], - refresh_token_expire_time: Optional[datetime], + refresh_token_expire_time: datetime, auth_role: AuthRoleEnum, created_at: datetime = None, modified_at: datetime = None, @@ -100,11 +100,11 @@ class AuthUser(TableABC): self._forgot_password_id = value @property - def refresh_token_expire_time(self) -> Optional[datetime]: + def refresh_token_expire_time(self) -> datetime: return self._refresh_token_expire_time @refresh_token_expire_time.setter - def refresh_token_expire_time(self, value: Optional[datetime]): + def refresh_token_expire_time(self, value: datetime): self._refresh_token_expire_time = value @property @@ -143,7 +143,7 @@ class AuthUser(TableABC): """) @staticmethod - def get_select_by_forgot_password_i_string(id: str) -> str: + def get_select_by_forgot_password_id_string(id: str) -> str: return str(f""" SELECT * FROM `AuthUsers` WHERE `ForgotPasswordId` = '{id}'; @@ -172,8 +172,8 @@ class AuthUser(TableABC): '{self._email}', '{self._password}', '{self._refresh_token}', - '{self._confirmation_id}', - '{self._forgot_password_id}', + '{"NULL" if self._confirmation_id is None else self._confirmation_id}', + '{"NULL" if self._forgot_password_id is None else self._forgot_password_id}', '{self._refresh_token_expire_time}', {self._auth_role_id.value}, '{self._created_at}', @@ -190,11 +190,11 @@ class AuthUser(TableABC): `EMail` = '{self._email}', `Password` = '{self._password}', `RefreshToken` = '{self._refresh_token}', - `ConfirmationId` = '{self._confirmation_id}', - `ForgotPasswordId` = '{self._forgot_password_id}', + `ConfirmationId` = '{"NULL" if self._confirmation_id is None else self._confirmation_id}', + `ForgotPasswordId` = '{"NULL" if self._forgot_password_id is None else self._forgot_password_id}', `RefreshTokenExpiryTime` = '{self._refresh_token_expire_time}', - `AutoRole` = {self._auth_role_id.value}, - `LastModifiedAt` = '{self._modified_at}' + `AuthRole` = {self._auth_role_id.value}, + `LastModifiedOn` = '{self._modified_at}' WHERE `AuthUsers`.`Id` = {self._auth_user_id}; """) diff --git a/src/bot_data/service/auth_user_repository_service.py b/src/bot_data/service/auth_user_repository_service.py index 2096113e34..4918b26980 100644 --- a/src/bot_data/service/auth_user_repository_service.py +++ b/src/bot_data/service/auth_user_repository_service.py @@ -20,18 +20,24 @@ class AuthUserRepositoryService(AuthUserRepositoryABC): AuthUserRepositoryABC.__init__(self) @staticmethod - def _user_from_result(result: tuple) -> AuthUser: + def _get_value_from_result(value: any) -> Optional[any]: + if isinstance(value, str) and 'NULL' in value: + return None + + return value + + def _user_from_result(self, result: tuple) -> AuthUser: return AuthUser( - result[1], - result[2], - result[3], - result[4], - result[5], - result[6], - result[7], - result[8], - AuthRoleEnum(result[9]), - id=result[0] + self._get_value_from_result(result[1]), + self._get_value_from_result(result[2]), + self._get_value_from_result(result[3]), + self._get_value_from_result(result[4]), + self._get_value_from_result(result[5]), + self._get_value_from_result(result[6]), + self._get_value_from_result(result[7]), + self._get_value_from_result(result[8]), + AuthRoleEnum(self._get_value_from_result(result[9])), + id=self._get_value_from_result(result[0]) ) def get_all_auth_users(self) -> List[AuthUser]: @@ -47,7 +53,6 @@ class AuthUserRepositoryService(AuthUserRepositoryABC): def get_filtered_auth_users(self, criteria: AuthUserSelectCriteria) -> FilteredResult: users = self.get_all_auth_users() self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_all_string()}') - query = users if criteria.first_name is not None and criteria.first_name != '': @@ -70,9 +75,9 @@ class AuthUserRepositoryService(AuthUserRepositoryABC): else: query = query.order_by(lambda x: getattr(x, criteria.sort_column)) - skip = criteria.page_size * criteria.page_index result = FilteredResult() result.total_count = query.count() + skip = criteria.page_size * criteria.page_index result.result = query.skip(skip).take(criteria.page_size) return result @@ -93,8 +98,8 @@ class AuthUserRepositoryService(AuthUserRepositoryABC): return self._user_from_result(result) def find_auth_user_by_confirmation_id(self, id: str) -> Optional[AuthUser]: - self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_by_email_string(id)}') - result = self._context.select(AuthUser.get_select_by_email_string(id)) + self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_by_confirmation_id_string(id)}') + result = self._context.select(AuthUser.get_select_by_confirmation_id_string(id)) if result is None or len(result) == 0: return None @@ -103,8 +108,8 @@ class AuthUserRepositoryService(AuthUserRepositoryABC): return self._user_from_result(result) def find_auth_user_by_forgot_password_id(self, id: str) -> Optional[AuthUser]: - self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_by_email_string(id)}') - result = self._context.select(AuthUser.get_select_by_email_string(id)) + self._logger.trace(__name__, f'Send SQL command: {AuthUser.get_select_by_forgot_password_id_string(id)}') + result = self._context.select(AuthUser.get_select_by_forgot_password_id_string(id)) if result is None or len(result) == 0: return None From 21fcfaaa7f5e9b0e0742f235f3ae85c48dec3420 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 15 Oct 2022 17:07:22 +0200 Subject: [PATCH 015/102] Fixed some random stuff #70 --- src/bot/bot.json | 2 +- src/bot/config/appsettings.edrafts-lapi.json | 2 +- src/bot_api/api.py | 3 ++- src/bot_data/db_context.py | 2 -- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/bot/bot.json b/src/bot/bot.json index df826bb7ef..89afddf9af 100644 --- a/src/bot/bot.json +++ b/src/bot/bot.json @@ -18,7 +18,7 @@ "Dependencies": [ "cpl-core==2022.10.0.post6", "cpl-translation==2022.10.0.post1", - "cpl-query==2022.10.0.post1", + "cpl-query==2022.10.0.post2", "cpl-discord==2022.10.0.post5" ], "DevDependencies": [ diff --git a/src/bot/config/appsettings.edrafts-lapi.json b/src/bot/config/appsettings.edrafts-lapi.json index 2e9e52a3d7..f0b9f1d172 100644 --- a/src/bot/config/appsettings.edrafts-lapi.json +++ b/src/bot/config/appsettings.edrafts-lapi.json @@ -27,7 +27,7 @@ "Database": { "Path": "logs/", "Filename": "database.log", - "ConsoleLogLevel": "DEBUG", + "ConsoleLogLevel": "TRACE", "FileLogLevel": "TRACE" }, "Message": { diff --git a/src/bot_api/api.py b/src/bot_api/api.py index 6a08c9a612..7930b861ce 100644 --- a/src/bot_api/api.py +++ b/src/bot_api/api.py @@ -77,4 +77,5 @@ class Api(Flask): self._logger.info(__name__, f'Starting API {self._apt_settings.host}:{self._apt_settings.port}') self._register_routes() from waitress import serve - serve(self, host=self._apt_settings.host, port=self._apt_settings.port) + # https://docs.pylonsproject.org/projects/waitress/en/stable/arguments.html + serve(self, host=self._apt_settings.host, port=self._apt_settings.port, threads=10, connection_limit=1000, channel_timeout=10) diff --git a/src/bot_data/db_context.py b/src/bot_data/db_context.py index fb0df29027..0f867228fb 100644 --- a/src/bot_data/db_context.py +++ b/src/bot_data/db_context.py @@ -16,8 +16,6 @@ class DBContext(DatabaseContext): try: self._logger.debug(__name__, "Connecting to database") self._db.connect(database_settings) - - self.save_changes() self._logger.info(__name__, "Connected to database") except Exception as e: self._logger.fatal(__name__, "Connecting to database failed", e) From 8e56ff6a8e21a1e888b0345a8a170817dfcc2407 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 15 Oct 2022 17:07:46 +0200 Subject: [PATCH 016/102] Set log level #70 --- src/bot/config/appsettings.edrafts-lapi.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bot/config/appsettings.edrafts-lapi.json b/src/bot/config/appsettings.edrafts-lapi.json index f0b9f1d172..2e9e52a3d7 100644 --- a/src/bot/config/appsettings.edrafts-lapi.json +++ b/src/bot/config/appsettings.edrafts-lapi.json @@ -27,7 +27,7 @@ "Database": { "Path": "logs/", "Filename": "database.log", - "ConsoleLogLevel": "TRACE", + "ConsoleLogLevel": "DEBUG", "FileLogLevel": "TRACE" }, "Message": { From 9da95f4dfb6a21efa1fda35e75c11cda8105a114 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 15 Oct 2022 17:25:49 +0200 Subject: [PATCH 017/102] Fixed update user #70 --- src/bot_api/json_processor.py | 11 ++++++-- src/bot_api/model/update_auth_user_dto.py | 8 +++--- src/bot_api/service/auth_service.py | 33 ++++++++++++----------- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/bot_api/json_processor.py b/src/bot_api/json_processor.py index e629258ecf..a0ea0ac159 100644 --- a/src/bot_api/json_processor.py +++ b/src/bot_api/json_processor.py @@ -16,12 +16,19 @@ class JSONProcessor: continue name = String.convert_to_camel_case(parameter.name) + name = name.replace('Dto', 'DTO') name_first_lower = String.first_to_lower(name) if name in values or name_first_lower in values: + value = '' if name in values: - args.append(values[name]) + value = values[name] else: - args.append(values[name_first_lower]) + value = values[name_first_lower] + + if isinstance(value, dict): + value = JSONProcessor.process(parameter.annotation, value) + + args.append(value) elif parameter.default != Parameter.empty: args.append(parameter.default) diff --git a/src/bot_api/model/update_auth_user_dto.py b/src/bot_api/model/update_auth_user_dto.py index 682f0122b4..9caa94738c 100644 --- a/src/bot_api/model/update_auth_user_dto.py +++ b/src/bot_api/model/update_auth_user_dto.py @@ -10,14 +10,14 @@ class UpdateAuthUserDTO(DtoABC): def __init__( self, - auth_user: AuthUserDTO, - new_auth_user: AuthUserDTO, + auth_user_dto: AuthUserDTO, + new_auth_user_dto: AuthUserDTO, change_password=False ): DtoABC.__init__(self) - self._auth_user = auth_user - self._new_auth_user = new_auth_user + self._auth_user = auth_user_dto + self._new_auth_user = new_auth_user_dto self._change_password = change_password @property diff --git a/src/bot_api/service/auth_service.py b/src/bot_api/service/auth_service.py index 07e750284c..ede6f15f18 100644 --- a/src/bot_api/service/auth_service.py +++ b/src/bot_api/service/auth_service.py @@ -191,12 +191,12 @@ class AuthService(AuthServiceABC): # update first name if update_user_dto.new_auth_user.first_name is not None and update_user_dto.auth_user.first_name != update_user_dto.new_auth_user.first_name: - user.FirstName = update_user_dto.new_auth_user.first_name + user.first_name = update_user_dto.new_auth_user.first_name # update last name if update_user_dto.new_auth_user.last_name is not None and update_user_dto.new_auth_user.last_name != '' and \ update_user_dto.auth_user.last_name != update_user_dto.new_auth_user.last_name: - user.LastName = update_user_dto.new_auth_user.last_name + user.last_name = update_user_dto.new_auth_user.last_name # update E-Mail if update_user_dto.new_auth_user.email is not None and update_user_dto.new_auth_user.email != '' and update_user_dto.auth_user.email != update_user_dto.new_auth_user.email: @@ -208,21 +208,22 @@ class AuthService(AuthServiceABC): is_existing_password_set = False is_new_password_set = False # hash passwords in DTOs - if update_user_dto.auth_user.Password is not None and update_user_dto.auth_user.Password != '': + if update_user_dto.auth_user.password is not None and update_user_dto.auth_user.password != '': is_existing_password_set = True - update_user_dto.auth_user.Password = self._hash_sha256(update_user_dto.auth_user.Password) + update_user_dto.auth_user.password = self._hash_sha256(update_user_dto.auth_user.password) - if update_user_dto.auth_user.Password != user.Password: + if update_user_dto.auth_user.password != user.password: raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong password') - if update_user_dto.new_auth_user.Password is not None and update_user_dto.new_auth_user.Password != '': + if update_user_dto.new_auth_user.password is not None and update_user_dto.new_auth_user.password != '': is_new_password_set = True - update_user_dto.new_auth_user.Password = self._hash_sha256(update_user_dto.new_auth_user.Password) + update_user_dto.new_auth_user.password = self._hash_sha256(update_user_dto.new_auth_user.password) # update password - if is_existing_password_set and is_new_password_set and update_user_dto.auth_user.Password != update_user_dto.new_auth_user.Password: - user.Password = update_user_dto.new_auth_user.Password + if is_existing_password_set and is_new_password_set and update_user_dto.auth_user.password != update_user_dto.new_auth_user.password: + user.password = update_user_dto.new_auth_user.password + self._auth_users.update_auth_user(user) self._db.save_changes() async def update_user_as_admin_async(self, update_user_dto: UpdateAuthUserDTO): @@ -242,31 +243,31 @@ class AuthService(AuthServiceABC): if user is None: raise ServiceException(ServiceErrorCode.InvalidUser, 'User not found') - if user.ConfirmationId is not None and update_user_dto.new_auth_user.is_confirmed: - user.ConfirmationId = None - elif user.ConfirmationId is None and not update_user_dto.new_auth_user.is_confirmed: + if user.confirmation_id is not None and update_user_dto.new_auth_user.is_confirmed: + user.confirmation_id = None + elif user.confirmation_id is None and not update_user_dto.new_auth_user.is_confirmed: user.confirmation_id = uuid.uuid4() # else # raise ServiceException(ServiceErrorCode.InvalidUser, 'E-Mail not confirmed') # update first name if update_user_dto.new_auth_user.first_name is not None and update_user_dto.auth_user.first_name != update_user_dto.new_auth_user.first_name: - user.FirstName = update_user_dto.new_auth_user.first_name + user.first_name = update_user_dto.new_auth_user.first_name # update last name if update_user_dto.new_auth_user.last_name is not None and update_user_dto.new_auth_user.last_name != '' and update_user_dto.auth_user.last_name != update_user_dto.new_auth_user.last_name: - user.LastName = update_user_dto.new_auth_user.last_name + user.last_name = update_user_dto.new_auth_user.last_name # update E-Mail if update_user_dto.new_auth_user.email is not None and update_user_dto.new_auth_user.email != '' and update_user_dto.auth_user.email != update_user_dto.new_auth_user.email: user_by_new_e_mail = self._auth_users.find_auth_user_by_email(update_user_dto.new_auth_user.email) if user_by_new_e_mail is not None: raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists') - user.EMail = update_user_dto.new_auth_user.email + user.email = update_user_dto.new_auth_user.email # update password if update_user_dto.change_password and update_user_dto.auth_user.password != update_user_dto.new_auth_user.password: - user.Password = self._hash_sha256(update_user_dto.new_auth_user.password) + user.password = self._hash_sha256(update_user_dto.new_auth_user.password) # update role if user.auth_role == update_user_dto.auth_user.auth_role and user.auth_role != update_user_dto.new_auth_user.auth_role: From 029b46d7de14411cd6d3dbe43a1a46d8473a2e48 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 15 Oct 2022 17:34:16 +0200 Subject: [PATCH 018/102] Build #70 --- src/bot_api/exception/__init__.py | 26 ++++++++++++++++++++++++++ src/bot_api/transformer/__init__.py | 26 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/bot_api/exception/__init__.py b/src/bot_api/exception/__init__.py index e69de29bb2..b37a52c4f5 100644 --- a/src/bot_api/exception/__init__.py +++ b/src/bot_api/exception/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +""" +bot Keksdose bot +~~~~~~~~~~~~~~~~~~~ + +Discord bot for the Keksdose discord Server + +:copyright: (c) 2022 sh-edraft.de +:license: MIT, see LICENSE for more details. + +""" + +__title__ = 'bot_api.exception' +__author__ = 'Sven Heidemann' +__license__ = 'MIT' +__copyright__ = 'Copyright (c) 2022 sh-edraft.de' +__version__ = '0.2.3' + +from collections import namedtuple + + +# imports: + +VersionInfo = namedtuple('VersionInfo', 'major minor micro') +version_info = VersionInfo(major='0', minor='2', micro='3') diff --git a/src/bot_api/transformer/__init__.py b/src/bot_api/transformer/__init__.py index e69de29bb2..4c614cb9e8 100644 --- a/src/bot_api/transformer/__init__.py +++ b/src/bot_api/transformer/__init__.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +""" +bot Keksdose bot +~~~~~~~~~~~~~~~~~~~ + +Discord bot for the Keksdose discord Server + +:copyright: (c) 2022 sh-edraft.de +:license: MIT, see LICENSE for more details. + +""" + +__title__ = 'bot_api.transformer' +__author__ = 'Sven Heidemann' +__license__ = 'MIT' +__copyright__ = 'Copyright (c) 2022 sh-edraft.de' +__version__ = '0.2.3' + +from collections import namedtuple + + +# imports: + +VersionInfo = namedtuple('VersionInfo', 'major minor micro') +version_info = VersionInfo(major='0', minor='2', micro='3') From ead3f69a69b5de9da222050d523dafc9b6cc36cb Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 15 Oct 2022 23:17:45 +0200 Subject: [PATCH 019/102] Moved bot to kdb-bot #70 --- cpl-workspace.json => kdb-bot/cpl-workspace.json | 0 docker-compose.yml => kdb-bot/docker-compose.yml | 0 dockerfile => kdb-bot/dockerfile | 0 {src => kdb-bot/src}/bot/__init__.py | 0 {src => kdb-bot/src}/bot/application.py | 0 {src => kdb-bot/src}/bot/bot | 0 {src => kdb-bot/src}/bot/bot.json | 0 {src => kdb-bot/src}/bot/config/appsettings.PC-Nick.json | 0 {src => kdb-bot/src}/bot/config/appsettings.development.json | 0 {src => kdb-bot/src}/bot/config/appsettings.edrafts-lapi.json | 0 .../src}/bot/config/appsettings.edrafts-pc-ubuntu.json | 0 {src => kdb-bot/src}/bot/config/appsettings.example.json | 0 {src => kdb-bot/src}/bot/config/appsettings.json | 0 {src => kdb-bot/src}/bot/config/appsettings.production.json | 0 {src => kdb-bot/src}/bot/config/appsettings.staging.json | 0 {src => kdb-bot/src}/bot/config/feature-flags.json | 0 {src => kdb-bot/src}/bot/main.py | 0 {src => kdb-bot/src}/bot/module_list.py | 0 {src => kdb-bot/src}/bot/startup.py | 0 {src => kdb-bot/src}/bot/startup_discord_extension.py | 0 {src => kdb-bot/src}/bot/startup_migration_extension.py | 0 {src => kdb-bot/src}/bot/startup_module_extension.py | 0 {src => kdb-bot/src}/bot/startup_settings_extension.py | 0 {src => kdb-bot/src}/bot/translation/de.json | 0 {src => kdb-bot/src}/bot_api/__init__.py | 0 {src => kdb-bot/src}/bot_api/abc/__init__.py | 0 {src => kdb-bot/src}/bot_api/abc/auth_service_abc.py | 0 {src => kdb-bot/src}/bot_api/abc/auth_user_transformer_abc.py | 0 {src => kdb-bot/src}/bot_api/abc/dto_abc.py | 0 {src => kdb-bot/src}/bot_api/abc/select_criteria_abc.py | 0 {src => kdb-bot/src}/bot_api/api.py | 0 {src => kdb-bot/src}/bot_api/api_module.py | 0 {src => kdb-bot/src}/bot_api/api_thread.py | 0 {src => kdb-bot/src}/bot_api/bot-api.json | 0 {src => kdb-bot/src}/bot_api/config/apisettings.development.json | 0 {src => kdb-bot/src}/bot_api/config/apisettings.edrafts-lapi.json | 0 .../src}/bot_api/config/apisettings.edrafts-pc-ubuntu.json | 0 {src => kdb-bot/src}/bot_api/config/apisettings.json | 0 {src => kdb-bot/src}/bot_api/config/apisettings.production.json | 0 {src => kdb-bot/src}/bot_api/config/apisettings.staging.json | 0 {src => kdb-bot/src}/bot_api/config/appsettings.PC-Nick.json | 0 {src => kdb-bot/src}/bot_api/configuration/__init__.py | 0 {src => kdb-bot/src}/bot_api/configuration/api_settings.py | 0 .../src}/bot_api/configuration/authentication_settings.py | 0 {src => kdb-bot/src}/bot_api/configuration/frontend_settings.py | 0 {src => kdb-bot/src}/bot_api/configuration/version_settings.py | 0 {src => kdb-bot/src}/bot_api/controller/__init__.py | 0 {src => kdb-bot/src}/bot_api/controller/auth_controller.py | 0 {src => kdb-bot/src}/bot_api/controller/gui_controller.py | 0 {src => kdb-bot/src}/bot_api/exception/__init__.py | 0 {src => kdb-bot/src}/bot_api/exception/service_error_code_enum.py | 0 {src => kdb-bot/src}/bot_api/exception/service_exception.py | 0 {src => kdb-bot/src}/bot_api/filter/__init__.py | 0 {src => kdb-bot/src}/bot_api/filter/auth_user_select_criteria.py | 0 {src => kdb-bot/src}/bot_api/json_processor.py | 0 {src => kdb-bot/src}/bot_api/logging/__init__.py | 0 {src => kdb-bot/src}/bot_api/logging/api_logger.py | 0 {src => kdb-bot/src}/bot_api/model/__init__.py | 0 {src => kdb-bot/src}/bot_api/model/auth_user_dto.py | 0 .../src}/bot_api/model/auth_user_filtered_result_dto.py | 0 {src => kdb-bot/src}/bot_api/model/email_string_dto.py | 0 {src => kdb-bot/src}/bot_api/model/error_dto.py | 0 {src => kdb-bot/src}/bot_api/model/reset_password_dto.py | 0 {src => kdb-bot/src}/bot_api/model/settings_dto.py | 0 {src => kdb-bot/src}/bot_api/model/token_dto.py | 0 {src => kdb-bot/src}/bot_api/model/update_auth_user_dto.py | 0 {src => kdb-bot/src}/bot_api/model/version_dto.py | 0 {src => kdb-bot/src}/bot_api/route/__init__.py | 0 {src => kdb-bot/src}/bot_api/route/route.py | 0 {src => kdb-bot/src}/bot_api/service/__init__.py | 0 {src => kdb-bot/src}/bot_api/service/auth_service.py | 0 {src => kdb-bot/src}/bot_api/transformer/__init__.py | 0 {src => kdb-bot/src}/bot_api/transformer/auth_user_transformer.py | 0 {src => kdb-bot/src}/bot_core/__init__.py | 0 {src => kdb-bot/src}/bot_core/abc/__init__.py | 0 {src => kdb-bot/src}/bot_core/abc/client_utils_service_abc.py | 0 {src => kdb-bot/src}/bot_core/abc/custom_file_logger_abc.py | 0 {src => kdb-bot/src}/bot_core/abc/message_service_abc.py | 0 {src => kdb-bot/src}/bot_core/abc/module_abc.py | 0 {src => kdb-bot/src}/bot_core/bot-core.json | 0 {src => kdb-bot/src}/bot_core/configuration/__init__.py | 0 .../src}/bot_core/configuration/bot_logging_settings.py | 0 {src => kdb-bot/src}/bot_core/configuration/bot_settings.py | 0 {src => kdb-bot/src}/bot_core/configuration/feature_flags_enum.py | 0 .../src}/bot_core/configuration/feature_flags_settings.py | 0 .../src}/bot_core/configuration/file_logging_settings.py | 0 {src => kdb-bot/src}/bot_core/configuration/server_settings.py | 0 {src => kdb-bot/src}/bot_core/core_extension/__init__.py | 0 .../src}/bot_core/core_extension/core_extension_module.py | 0 .../src}/bot_core/core_extension/core_extension_on_ready_event.py | 0 {src => kdb-bot/src}/bot_core/core_module.py | 0 {src => kdb-bot/src}/bot_core/events/__init__.py | 0 {src => kdb-bot/src}/bot_core/events/core_on_ready_event.py | 0 {src => kdb-bot/src}/bot_core/helper/__init__.py | 0 {src => kdb-bot/src}/bot_core/helper/log_message_helper.py | 0 {src => kdb-bot/src}/bot_core/logging/__init__.py | 0 {src => kdb-bot/src}/bot_core/logging/command_logger.py | 0 {src => kdb-bot/src}/bot_core/logging/database_logger.py | 0 {src => kdb-bot/src}/bot_core/logging/message_logger.py | 0 {src => kdb-bot/src}/bot_core/pipes/__init__.py | 0 {src => kdb-bot/src}/bot_core/pipes/date_time_offset_pipe.py | 0 {src => kdb-bot/src}/bot_core/service/__init__.py | 0 {src => kdb-bot/src}/bot_core/service/client_utils_service.py | 0 {src => kdb-bot/src}/bot_core/service/message_service.py | 0 {src => kdb-bot/src}/bot_data/__init__.py | 0 {src => kdb-bot/src}/bot_data/abc/__init__.py | 0 {src => kdb-bot/src}/bot_data/abc/auth_user_repository_abc.py | 0 {src => kdb-bot/src}/bot_data/abc/auto_role_repository_abc.py | 0 {src => kdb-bot/src}/bot_data/abc/client_repository_abc.py | 0 {src => kdb-bot/src}/bot_data/abc/known_user_repository_abc.py | 0 {src => kdb-bot/src}/bot_data/abc/migration_abc.py | 0 {src => kdb-bot/src}/bot_data/abc/server_repository_abc.py | 0 .../src}/bot_data/abc/user_joined_server_repository_abc.py | 0 .../src}/bot_data/abc/user_joined_voice_channel_abc.py | 0 {src => kdb-bot/src}/bot_data/abc/user_repository_abc.py | 0 {src => kdb-bot/src}/bot_data/bot-data.json | 0 {src => kdb-bot/src}/bot_data/data_module.py | 0 {src => kdb-bot/src}/bot_data/db_context.py | 0 {src => kdb-bot/src}/bot_data/filtered_result.py | 0 {src => kdb-bot/src}/bot_data/migration/__init__.py | 0 {src => kdb-bot/src}/bot_data/migration/api_migration.py | 0 {src => kdb-bot/src}/bot_data/migration/auto_role_migration.py | 0 {src => kdb-bot/src}/bot_data/migration/initial_migration.py | 0 {src => kdb-bot/src}/bot_data/model/__init__.py | 0 {src => kdb-bot/src}/bot_data/model/auth_role_enum.py | 0 {src => kdb-bot/src}/bot_data/model/auth_user.py | 0 {src => kdb-bot/src}/bot_data/model/auto_role.py | 0 {src => kdb-bot/src}/bot_data/model/auto_role_rule.py | 0 {src => kdb-bot/src}/bot_data/model/client.py | 0 {src => kdb-bot/src}/bot_data/model/known_user.py | 0 {src => kdb-bot/src}/bot_data/model/migration_history.py | 0 {src => kdb-bot/src}/bot_data/model/server.py | 0 {src => kdb-bot/src}/bot_data/model/user.py | 0 {src => kdb-bot/src}/bot_data/model/user_joined_server.py | 0 {src => kdb-bot/src}/bot_data/model/user_joined_voice_channel.py | 0 {src => kdb-bot/src}/bot_data/service/__init__.py | 0 .../src}/bot_data/service/auth_user_repository_service.py | 0 .../src}/bot_data/service/auto_role_repository_service.py | 0 .../src}/bot_data/service/client_repository_service.py | 0 .../src}/bot_data/service/known_user_repository_service.py | 0 {src => kdb-bot/src}/bot_data/service/migration_service.py | 0 .../src}/bot_data/service/server_repository_service.py | 0 .../bot_data/service/user_joined_server_repository_service.py | 0 .../src}/bot_data/service/user_joined_voice_channel_service.py | 0 {src => kdb-bot/src}/bot_data/service/user_repository_service.py | 0 {src => kdb-bot/src}/modules/__init__.py | 0 {src => kdb-bot/src}/modules/admin/__init__.py | 0 {src => kdb-bot/src}/modules/admin/admin.json | 0 {src => kdb-bot/src}/modules/admin/admin_module.py | 0 {src => kdb-bot/src}/modules/admin/command/__init__.py | 0 {src => kdb-bot/src}/modules/admin/command/restart_command.py | 0 {src => kdb-bot/src}/modules/admin/command/shutdown_command.py | 0 {src => kdb-bot/src}/modules/auto_role/__init__.py | 0 {src => kdb-bot/src}/modules/auto_role/auto-role.json | 0 {src => kdb-bot/src}/modules/auto_role/auto_role_module.py | 0 {src => kdb-bot/src}/modules/auto_role/command/__init__.py | 0 {src => kdb-bot/src}/modules/auto_role/command/auto_role_group.py | 0 {src => kdb-bot/src}/modules/auto_role/events/__init__.py | 0 .../modules/auto_role/events/auto_role_on_raw_reaction_add.py | 0 .../modules/auto_role/events/auto_role_on_raw_reaction_remove.py | 0 {src => kdb-bot/src}/modules/auto_role/helper/__init__.py | 0 {src => kdb-bot/src}/modules/auto_role/helper/reaction_handler.py | 0 {src => kdb-bot/src}/modules/base/__init__.py | 0 {src => kdb-bot/src}/modules/base/abc/__init__.py | 0 {src => kdb-bot/src}/modules/base/abc/base_helper_abc.py | 0 {src => kdb-bot/src}/modules/base/base.json | 0 {src => kdb-bot/src}/modules/base/base_module.py | 0 {src => kdb-bot/src}/modules/base/command/__init__.py | 0 {src => kdb-bot/src}/modules/base/command/afk_command.py | 0 {src => kdb-bot/src}/modules/base/command/help_command.py | 0 {src => kdb-bot/src}/modules/base/command/info_command.py | 0 {src => kdb-bot/src}/modules/base/command/ping_command.py | 0 {src => kdb-bot/src}/modules/base/configuration/__init__.py | 0 .../src}/modules/base/configuration/base_server_settings.py | 0 {src => kdb-bot/src}/modules/base/configuration/base_settings.py | 0 {src => kdb-bot/src}/modules/base/events/__init__.py | 0 .../src}/modules/base/events/base_on_command_error_event.py | 0 {src => kdb-bot/src}/modules/base/events/base_on_command_event.py | 0 .../src}/modules/base/events/base_on_member_join_event.py | 0 .../src}/modules/base/events/base_on_member_remove_event.py | 0 {src => kdb-bot/src}/modules/base/events/base_on_message_event.py | 0 .../src}/modules/base/events/base_on_voice_state_update_event.py | 0 {src => kdb-bot/src}/modules/base/service/__init__.py | 0 {src => kdb-bot/src}/modules/base/service/base_helper_service.py | 0 {src => kdb-bot/src}/modules/boot_log/__init__.py | 0 {src => kdb-bot/src}/modules/boot_log/boot-log.json | 0 {src => kdb-bot/src}/modules/boot_log/boot_log_extension.py | 0 {src => kdb-bot/src}/modules/boot_log/boot_log_module.py | 0 {src => kdb-bot/src}/modules/boot_log/boot_log_on_ready_event.py | 0 {src => kdb-bot/src}/modules/boot_log/configuration/__init__.py | 0 .../modules/boot_log/configuration/boot_log_server_settings.py | 0 .../src}/modules/boot_log/configuration/boot_log_settings.py | 0 {src => kdb-bot/src}/modules/database/__init__.py | 0 {src => kdb-bot/src}/modules/database/database.json | 0 {src => kdb-bot/src}/modules/database/database_extension.py | 0 {src => kdb-bot/src}/modules/database/database_module.py | 0 {src => kdb-bot/src}/modules/database/database_on_ready_event.py | 0 {src => kdb-bot/src}/modules/moderator/__init__.py | 0 {src => kdb-bot/src}/modules/moderator/command/__init__.py | 0 {src => kdb-bot/src}/modules/moderator/command/purge_command.py | 0 {src => kdb-bot/src}/modules/moderator/command/user_group.py | 0 {src => kdb-bot/src}/modules/moderator/moderator.json | 0 {src => kdb-bot/src}/modules/moderator/moderator_module.py | 0 {src => kdb-bot/src}/modules/permission/__init__.py | 0 {src => kdb-bot/src}/modules/permission/abc/__init__.py | 0 .../src}/modules/permission/abc/permission_service_abc.py | 0 {src => kdb-bot/src}/modules/permission/configuration/__init__.py | 0 .../permission/configuration/permission_server_settings.py | 0 .../src}/modules/permission/configuration/permission_settings.py | 0 {src => kdb-bot/src}/modules/permission/events/__init__.py | 0 .../permission/events/permission_on_member_update_event.py | 0 .../src}/modules/permission/events/permission_on_ready_event.py | 0 {src => kdb-bot/src}/modules/permission/permission.json | 0 {src => kdb-bot/src}/modules/permission/permission_module.py | 0 {src => kdb-bot/src}/modules/permission/service/__init__.py | 0 .../src}/modules/permission/service/permission_service.py | 0 216 files changed, 0 insertions(+), 0 deletions(-) rename cpl-workspace.json => kdb-bot/cpl-workspace.json (100%) rename docker-compose.yml => kdb-bot/docker-compose.yml (100%) rename dockerfile => kdb-bot/dockerfile (100%) rename {src => kdb-bot/src}/bot/__init__.py (100%) rename {src => kdb-bot/src}/bot/application.py (100%) rename {src => kdb-bot/src}/bot/bot (100%) rename {src => kdb-bot/src}/bot/bot.json (100%) rename {src => kdb-bot/src}/bot/config/appsettings.PC-Nick.json (100%) rename {src => kdb-bot/src}/bot/config/appsettings.development.json (100%) rename {src => kdb-bot/src}/bot/config/appsettings.edrafts-lapi.json (100%) rename {src => kdb-bot/src}/bot/config/appsettings.edrafts-pc-ubuntu.json (100%) rename {src => kdb-bot/src}/bot/config/appsettings.example.json (100%) rename {src => kdb-bot/src}/bot/config/appsettings.json (100%) rename {src => kdb-bot/src}/bot/config/appsettings.production.json (100%) rename {src => kdb-bot/src}/bot/config/appsettings.staging.json (100%) rename {src => kdb-bot/src}/bot/config/feature-flags.json (100%) rename {src => kdb-bot/src}/bot/main.py (100%) rename {src => kdb-bot/src}/bot/module_list.py (100%) rename {src => kdb-bot/src}/bot/startup.py (100%) rename {src => kdb-bot/src}/bot/startup_discord_extension.py (100%) rename {src => kdb-bot/src}/bot/startup_migration_extension.py (100%) rename {src => kdb-bot/src}/bot/startup_module_extension.py (100%) rename {src => kdb-bot/src}/bot/startup_settings_extension.py (100%) rename {src => kdb-bot/src}/bot/translation/de.json (100%) rename {src => kdb-bot/src}/bot_api/__init__.py (100%) rename {src => kdb-bot/src}/bot_api/abc/__init__.py (100%) rename {src => kdb-bot/src}/bot_api/abc/auth_service_abc.py (100%) rename {src => kdb-bot/src}/bot_api/abc/auth_user_transformer_abc.py (100%) rename {src => kdb-bot/src}/bot_api/abc/dto_abc.py (100%) rename {src => kdb-bot/src}/bot_api/abc/select_criteria_abc.py (100%) rename {src => kdb-bot/src}/bot_api/api.py (100%) rename {src => kdb-bot/src}/bot_api/api_module.py (100%) rename {src => kdb-bot/src}/bot_api/api_thread.py (100%) rename {src => kdb-bot/src}/bot_api/bot-api.json (100%) rename {src => kdb-bot/src}/bot_api/config/apisettings.development.json (100%) rename {src => kdb-bot/src}/bot_api/config/apisettings.edrafts-lapi.json (100%) rename {src => kdb-bot/src}/bot_api/config/apisettings.edrafts-pc-ubuntu.json (100%) rename {src => kdb-bot/src}/bot_api/config/apisettings.json (100%) rename {src => kdb-bot/src}/bot_api/config/apisettings.production.json (100%) rename {src => kdb-bot/src}/bot_api/config/apisettings.staging.json (100%) rename {src => kdb-bot/src}/bot_api/config/appsettings.PC-Nick.json (100%) rename {src => kdb-bot/src}/bot_api/configuration/__init__.py (100%) rename {src => kdb-bot/src}/bot_api/configuration/api_settings.py (100%) rename {src => kdb-bot/src}/bot_api/configuration/authentication_settings.py (100%) rename {src => kdb-bot/src}/bot_api/configuration/frontend_settings.py (100%) rename {src => kdb-bot/src}/bot_api/configuration/version_settings.py (100%) rename {src => kdb-bot/src}/bot_api/controller/__init__.py (100%) rename {src => kdb-bot/src}/bot_api/controller/auth_controller.py (100%) rename {src => kdb-bot/src}/bot_api/controller/gui_controller.py (100%) rename {src => kdb-bot/src}/bot_api/exception/__init__.py (100%) rename {src => kdb-bot/src}/bot_api/exception/service_error_code_enum.py (100%) rename {src => kdb-bot/src}/bot_api/exception/service_exception.py (100%) rename {src => kdb-bot/src}/bot_api/filter/__init__.py (100%) rename {src => kdb-bot/src}/bot_api/filter/auth_user_select_criteria.py (100%) rename {src => kdb-bot/src}/bot_api/json_processor.py (100%) rename {src => kdb-bot/src}/bot_api/logging/__init__.py (100%) rename {src => kdb-bot/src}/bot_api/logging/api_logger.py (100%) rename {src => kdb-bot/src}/bot_api/model/__init__.py (100%) rename {src => kdb-bot/src}/bot_api/model/auth_user_dto.py (100%) rename {src => kdb-bot/src}/bot_api/model/auth_user_filtered_result_dto.py (100%) rename {src => kdb-bot/src}/bot_api/model/email_string_dto.py (100%) rename {src => kdb-bot/src}/bot_api/model/error_dto.py (100%) rename {src => kdb-bot/src}/bot_api/model/reset_password_dto.py (100%) rename {src => kdb-bot/src}/bot_api/model/settings_dto.py (100%) rename {src => kdb-bot/src}/bot_api/model/token_dto.py (100%) rename {src => kdb-bot/src}/bot_api/model/update_auth_user_dto.py (100%) rename {src => kdb-bot/src}/bot_api/model/version_dto.py (100%) rename {src => kdb-bot/src}/bot_api/route/__init__.py (100%) rename {src => kdb-bot/src}/bot_api/route/route.py (100%) rename {src => kdb-bot/src}/bot_api/service/__init__.py (100%) rename {src => kdb-bot/src}/bot_api/service/auth_service.py (100%) rename {src => kdb-bot/src}/bot_api/transformer/__init__.py (100%) rename {src => kdb-bot/src}/bot_api/transformer/auth_user_transformer.py (100%) rename {src => kdb-bot/src}/bot_core/__init__.py (100%) rename {src => kdb-bot/src}/bot_core/abc/__init__.py (100%) rename {src => kdb-bot/src}/bot_core/abc/client_utils_service_abc.py (100%) rename {src => kdb-bot/src}/bot_core/abc/custom_file_logger_abc.py (100%) rename {src => kdb-bot/src}/bot_core/abc/message_service_abc.py (100%) rename {src => kdb-bot/src}/bot_core/abc/module_abc.py (100%) rename {src => kdb-bot/src}/bot_core/bot-core.json (100%) rename {src => kdb-bot/src}/bot_core/configuration/__init__.py (100%) rename {src => kdb-bot/src}/bot_core/configuration/bot_logging_settings.py (100%) rename {src => kdb-bot/src}/bot_core/configuration/bot_settings.py (100%) rename {src => kdb-bot/src}/bot_core/configuration/feature_flags_enum.py (100%) rename {src => kdb-bot/src}/bot_core/configuration/feature_flags_settings.py (100%) rename {src => kdb-bot/src}/bot_core/configuration/file_logging_settings.py (100%) rename {src => kdb-bot/src}/bot_core/configuration/server_settings.py (100%) rename {src => kdb-bot/src}/bot_core/core_extension/__init__.py (100%) rename {src => kdb-bot/src}/bot_core/core_extension/core_extension_module.py (100%) rename {src => kdb-bot/src}/bot_core/core_extension/core_extension_on_ready_event.py (100%) rename {src => kdb-bot/src}/bot_core/core_module.py (100%) rename {src => kdb-bot/src}/bot_core/events/__init__.py (100%) rename {src => kdb-bot/src}/bot_core/events/core_on_ready_event.py (100%) rename {src => kdb-bot/src}/bot_core/helper/__init__.py (100%) rename {src => kdb-bot/src}/bot_core/helper/log_message_helper.py (100%) rename {src => kdb-bot/src}/bot_core/logging/__init__.py (100%) rename {src => kdb-bot/src}/bot_core/logging/command_logger.py (100%) rename {src => kdb-bot/src}/bot_core/logging/database_logger.py (100%) rename {src => kdb-bot/src}/bot_core/logging/message_logger.py (100%) rename {src => kdb-bot/src}/bot_core/pipes/__init__.py (100%) rename {src => kdb-bot/src}/bot_core/pipes/date_time_offset_pipe.py (100%) rename {src => kdb-bot/src}/bot_core/service/__init__.py (100%) rename {src => kdb-bot/src}/bot_core/service/client_utils_service.py (100%) rename {src => kdb-bot/src}/bot_core/service/message_service.py (100%) rename {src => kdb-bot/src}/bot_data/__init__.py (100%) rename {src => kdb-bot/src}/bot_data/abc/__init__.py (100%) rename {src => kdb-bot/src}/bot_data/abc/auth_user_repository_abc.py (100%) rename {src => kdb-bot/src}/bot_data/abc/auto_role_repository_abc.py (100%) rename {src => kdb-bot/src}/bot_data/abc/client_repository_abc.py (100%) rename {src => kdb-bot/src}/bot_data/abc/known_user_repository_abc.py (100%) rename {src => kdb-bot/src}/bot_data/abc/migration_abc.py (100%) rename {src => kdb-bot/src}/bot_data/abc/server_repository_abc.py (100%) rename {src => kdb-bot/src}/bot_data/abc/user_joined_server_repository_abc.py (100%) rename {src => kdb-bot/src}/bot_data/abc/user_joined_voice_channel_abc.py (100%) rename {src => kdb-bot/src}/bot_data/abc/user_repository_abc.py (100%) rename {src => kdb-bot/src}/bot_data/bot-data.json (100%) rename {src => kdb-bot/src}/bot_data/data_module.py (100%) rename {src => kdb-bot/src}/bot_data/db_context.py (100%) rename {src => kdb-bot/src}/bot_data/filtered_result.py (100%) rename {src => kdb-bot/src}/bot_data/migration/__init__.py (100%) rename {src => kdb-bot/src}/bot_data/migration/api_migration.py (100%) rename {src => kdb-bot/src}/bot_data/migration/auto_role_migration.py (100%) rename {src => kdb-bot/src}/bot_data/migration/initial_migration.py (100%) rename {src => kdb-bot/src}/bot_data/model/__init__.py (100%) rename {src => kdb-bot/src}/bot_data/model/auth_role_enum.py (100%) rename {src => kdb-bot/src}/bot_data/model/auth_user.py (100%) rename {src => kdb-bot/src}/bot_data/model/auto_role.py (100%) rename {src => kdb-bot/src}/bot_data/model/auto_role_rule.py (100%) rename {src => kdb-bot/src}/bot_data/model/client.py (100%) rename {src => kdb-bot/src}/bot_data/model/known_user.py (100%) rename {src => kdb-bot/src}/bot_data/model/migration_history.py (100%) rename {src => kdb-bot/src}/bot_data/model/server.py (100%) rename {src => kdb-bot/src}/bot_data/model/user.py (100%) rename {src => kdb-bot/src}/bot_data/model/user_joined_server.py (100%) rename {src => kdb-bot/src}/bot_data/model/user_joined_voice_channel.py (100%) rename {src => kdb-bot/src}/bot_data/service/__init__.py (100%) rename {src => kdb-bot/src}/bot_data/service/auth_user_repository_service.py (100%) rename {src => kdb-bot/src}/bot_data/service/auto_role_repository_service.py (100%) rename {src => kdb-bot/src}/bot_data/service/client_repository_service.py (100%) rename {src => kdb-bot/src}/bot_data/service/known_user_repository_service.py (100%) rename {src => kdb-bot/src}/bot_data/service/migration_service.py (100%) rename {src => kdb-bot/src}/bot_data/service/server_repository_service.py (100%) rename {src => kdb-bot/src}/bot_data/service/user_joined_server_repository_service.py (100%) rename {src => kdb-bot/src}/bot_data/service/user_joined_voice_channel_service.py (100%) rename {src => kdb-bot/src}/bot_data/service/user_repository_service.py (100%) rename {src => kdb-bot/src}/modules/__init__.py (100%) rename {src => kdb-bot/src}/modules/admin/__init__.py (100%) rename {src => kdb-bot/src}/modules/admin/admin.json (100%) rename {src => kdb-bot/src}/modules/admin/admin_module.py (100%) rename {src => kdb-bot/src}/modules/admin/command/__init__.py (100%) rename {src => kdb-bot/src}/modules/admin/command/restart_command.py (100%) rename {src => kdb-bot/src}/modules/admin/command/shutdown_command.py (100%) rename {src => kdb-bot/src}/modules/auto_role/__init__.py (100%) rename {src => kdb-bot/src}/modules/auto_role/auto-role.json (100%) rename {src => kdb-bot/src}/modules/auto_role/auto_role_module.py (100%) rename {src => kdb-bot/src}/modules/auto_role/command/__init__.py (100%) rename {src => kdb-bot/src}/modules/auto_role/command/auto_role_group.py (100%) rename {src => kdb-bot/src}/modules/auto_role/events/__init__.py (100%) rename {src => kdb-bot/src}/modules/auto_role/events/auto_role_on_raw_reaction_add.py (100%) rename {src => kdb-bot/src}/modules/auto_role/events/auto_role_on_raw_reaction_remove.py (100%) rename {src => kdb-bot/src}/modules/auto_role/helper/__init__.py (100%) rename {src => kdb-bot/src}/modules/auto_role/helper/reaction_handler.py (100%) rename {src => kdb-bot/src}/modules/base/__init__.py (100%) rename {src => kdb-bot/src}/modules/base/abc/__init__.py (100%) rename {src => kdb-bot/src}/modules/base/abc/base_helper_abc.py (100%) rename {src => kdb-bot/src}/modules/base/base.json (100%) rename {src => kdb-bot/src}/modules/base/base_module.py (100%) rename {src => kdb-bot/src}/modules/base/command/__init__.py (100%) rename {src => kdb-bot/src}/modules/base/command/afk_command.py (100%) rename {src => kdb-bot/src}/modules/base/command/help_command.py (100%) rename {src => kdb-bot/src}/modules/base/command/info_command.py (100%) rename {src => kdb-bot/src}/modules/base/command/ping_command.py (100%) rename {src => kdb-bot/src}/modules/base/configuration/__init__.py (100%) rename {src => kdb-bot/src}/modules/base/configuration/base_server_settings.py (100%) rename {src => kdb-bot/src}/modules/base/configuration/base_settings.py (100%) rename {src => kdb-bot/src}/modules/base/events/__init__.py (100%) rename {src => kdb-bot/src}/modules/base/events/base_on_command_error_event.py (100%) rename {src => kdb-bot/src}/modules/base/events/base_on_command_event.py (100%) rename {src => kdb-bot/src}/modules/base/events/base_on_member_join_event.py (100%) rename {src => kdb-bot/src}/modules/base/events/base_on_member_remove_event.py (100%) rename {src => kdb-bot/src}/modules/base/events/base_on_message_event.py (100%) rename {src => kdb-bot/src}/modules/base/events/base_on_voice_state_update_event.py (100%) rename {src => kdb-bot/src}/modules/base/service/__init__.py (100%) rename {src => kdb-bot/src}/modules/base/service/base_helper_service.py (100%) rename {src => kdb-bot/src}/modules/boot_log/__init__.py (100%) rename {src => kdb-bot/src}/modules/boot_log/boot-log.json (100%) rename {src => kdb-bot/src}/modules/boot_log/boot_log_extension.py (100%) rename {src => kdb-bot/src}/modules/boot_log/boot_log_module.py (100%) rename {src => kdb-bot/src}/modules/boot_log/boot_log_on_ready_event.py (100%) rename {src => kdb-bot/src}/modules/boot_log/configuration/__init__.py (100%) rename {src => kdb-bot/src}/modules/boot_log/configuration/boot_log_server_settings.py (100%) rename {src => kdb-bot/src}/modules/boot_log/configuration/boot_log_settings.py (100%) rename {src => kdb-bot/src}/modules/database/__init__.py (100%) rename {src => kdb-bot/src}/modules/database/database.json (100%) rename {src => kdb-bot/src}/modules/database/database_extension.py (100%) rename {src => kdb-bot/src}/modules/database/database_module.py (100%) rename {src => kdb-bot/src}/modules/database/database_on_ready_event.py (100%) rename {src => kdb-bot/src}/modules/moderator/__init__.py (100%) rename {src => kdb-bot/src}/modules/moderator/command/__init__.py (100%) rename {src => kdb-bot/src}/modules/moderator/command/purge_command.py (100%) rename {src => kdb-bot/src}/modules/moderator/command/user_group.py (100%) rename {src => kdb-bot/src}/modules/moderator/moderator.json (100%) rename {src => kdb-bot/src}/modules/moderator/moderator_module.py (100%) rename {src => kdb-bot/src}/modules/permission/__init__.py (100%) rename {src => kdb-bot/src}/modules/permission/abc/__init__.py (100%) rename {src => kdb-bot/src}/modules/permission/abc/permission_service_abc.py (100%) rename {src => kdb-bot/src}/modules/permission/configuration/__init__.py (100%) rename {src => kdb-bot/src}/modules/permission/configuration/permission_server_settings.py (100%) rename {src => kdb-bot/src}/modules/permission/configuration/permission_settings.py (100%) rename {src => kdb-bot/src}/modules/permission/events/__init__.py (100%) rename {src => kdb-bot/src}/modules/permission/events/permission_on_member_update_event.py (100%) rename {src => kdb-bot/src}/modules/permission/events/permission_on_ready_event.py (100%) rename {src => kdb-bot/src}/modules/permission/permission.json (100%) rename {src => kdb-bot/src}/modules/permission/permission_module.py (100%) rename {src => kdb-bot/src}/modules/permission/service/__init__.py (100%) rename {src => kdb-bot/src}/modules/permission/service/permission_service.py (100%) diff --git a/cpl-workspace.json b/kdb-bot/cpl-workspace.json similarity index 100% rename from cpl-workspace.json rename to kdb-bot/cpl-workspace.json diff --git a/docker-compose.yml b/kdb-bot/docker-compose.yml similarity index 100% rename from docker-compose.yml rename to kdb-bot/docker-compose.yml diff --git a/dockerfile b/kdb-bot/dockerfile similarity index 100% rename from dockerfile rename to kdb-bot/dockerfile diff --git a/src/bot/__init__.py b/kdb-bot/src/bot/__init__.py similarity index 100% rename from src/bot/__init__.py rename to kdb-bot/src/bot/__init__.py diff --git a/src/bot/application.py b/kdb-bot/src/bot/application.py similarity index 100% rename from src/bot/application.py rename to kdb-bot/src/bot/application.py diff --git a/src/bot/bot b/kdb-bot/src/bot/bot similarity index 100% rename from src/bot/bot rename to kdb-bot/src/bot/bot diff --git a/src/bot/bot.json b/kdb-bot/src/bot/bot.json similarity index 100% rename from src/bot/bot.json rename to kdb-bot/src/bot/bot.json diff --git a/src/bot/config/appsettings.PC-Nick.json b/kdb-bot/src/bot/config/appsettings.PC-Nick.json similarity index 100% rename from src/bot/config/appsettings.PC-Nick.json rename to kdb-bot/src/bot/config/appsettings.PC-Nick.json diff --git a/src/bot/config/appsettings.development.json b/kdb-bot/src/bot/config/appsettings.development.json similarity index 100% rename from src/bot/config/appsettings.development.json rename to kdb-bot/src/bot/config/appsettings.development.json diff --git a/src/bot/config/appsettings.edrafts-lapi.json b/kdb-bot/src/bot/config/appsettings.edrafts-lapi.json similarity index 100% rename from src/bot/config/appsettings.edrafts-lapi.json rename to kdb-bot/src/bot/config/appsettings.edrafts-lapi.json diff --git a/src/bot/config/appsettings.edrafts-pc-ubuntu.json b/kdb-bot/src/bot/config/appsettings.edrafts-pc-ubuntu.json similarity index 100% rename from src/bot/config/appsettings.edrafts-pc-ubuntu.json rename to kdb-bot/src/bot/config/appsettings.edrafts-pc-ubuntu.json diff --git a/src/bot/config/appsettings.example.json b/kdb-bot/src/bot/config/appsettings.example.json similarity index 100% rename from src/bot/config/appsettings.example.json rename to kdb-bot/src/bot/config/appsettings.example.json diff --git a/src/bot/config/appsettings.json b/kdb-bot/src/bot/config/appsettings.json similarity index 100% rename from src/bot/config/appsettings.json rename to kdb-bot/src/bot/config/appsettings.json diff --git a/src/bot/config/appsettings.production.json b/kdb-bot/src/bot/config/appsettings.production.json similarity index 100% rename from src/bot/config/appsettings.production.json rename to kdb-bot/src/bot/config/appsettings.production.json diff --git a/src/bot/config/appsettings.staging.json b/kdb-bot/src/bot/config/appsettings.staging.json similarity index 100% rename from src/bot/config/appsettings.staging.json rename to kdb-bot/src/bot/config/appsettings.staging.json diff --git a/src/bot/config/feature-flags.json b/kdb-bot/src/bot/config/feature-flags.json similarity index 100% rename from src/bot/config/feature-flags.json rename to kdb-bot/src/bot/config/feature-flags.json diff --git a/src/bot/main.py b/kdb-bot/src/bot/main.py similarity index 100% rename from src/bot/main.py rename to kdb-bot/src/bot/main.py diff --git a/src/bot/module_list.py b/kdb-bot/src/bot/module_list.py similarity index 100% rename from src/bot/module_list.py rename to kdb-bot/src/bot/module_list.py diff --git a/src/bot/startup.py b/kdb-bot/src/bot/startup.py similarity index 100% rename from src/bot/startup.py rename to kdb-bot/src/bot/startup.py diff --git a/src/bot/startup_discord_extension.py b/kdb-bot/src/bot/startup_discord_extension.py similarity index 100% rename from src/bot/startup_discord_extension.py rename to kdb-bot/src/bot/startup_discord_extension.py diff --git a/src/bot/startup_migration_extension.py b/kdb-bot/src/bot/startup_migration_extension.py similarity index 100% rename from src/bot/startup_migration_extension.py rename to kdb-bot/src/bot/startup_migration_extension.py diff --git a/src/bot/startup_module_extension.py b/kdb-bot/src/bot/startup_module_extension.py similarity index 100% rename from src/bot/startup_module_extension.py rename to kdb-bot/src/bot/startup_module_extension.py diff --git a/src/bot/startup_settings_extension.py b/kdb-bot/src/bot/startup_settings_extension.py similarity index 100% rename from src/bot/startup_settings_extension.py rename to kdb-bot/src/bot/startup_settings_extension.py diff --git a/src/bot/translation/de.json b/kdb-bot/src/bot/translation/de.json similarity index 100% rename from src/bot/translation/de.json rename to kdb-bot/src/bot/translation/de.json diff --git a/src/bot_api/__init__.py b/kdb-bot/src/bot_api/__init__.py similarity index 100% rename from src/bot_api/__init__.py rename to kdb-bot/src/bot_api/__init__.py diff --git a/src/bot_api/abc/__init__.py b/kdb-bot/src/bot_api/abc/__init__.py similarity index 100% rename from src/bot_api/abc/__init__.py rename to kdb-bot/src/bot_api/abc/__init__.py diff --git a/src/bot_api/abc/auth_service_abc.py b/kdb-bot/src/bot_api/abc/auth_service_abc.py similarity index 100% rename from src/bot_api/abc/auth_service_abc.py rename to kdb-bot/src/bot_api/abc/auth_service_abc.py diff --git a/src/bot_api/abc/auth_user_transformer_abc.py b/kdb-bot/src/bot_api/abc/auth_user_transformer_abc.py similarity index 100% rename from src/bot_api/abc/auth_user_transformer_abc.py rename to kdb-bot/src/bot_api/abc/auth_user_transformer_abc.py diff --git a/src/bot_api/abc/dto_abc.py b/kdb-bot/src/bot_api/abc/dto_abc.py similarity index 100% rename from src/bot_api/abc/dto_abc.py rename to kdb-bot/src/bot_api/abc/dto_abc.py diff --git a/src/bot_api/abc/select_criteria_abc.py b/kdb-bot/src/bot_api/abc/select_criteria_abc.py similarity index 100% rename from src/bot_api/abc/select_criteria_abc.py rename to kdb-bot/src/bot_api/abc/select_criteria_abc.py diff --git a/src/bot_api/api.py b/kdb-bot/src/bot_api/api.py similarity index 100% rename from src/bot_api/api.py rename to kdb-bot/src/bot_api/api.py diff --git a/src/bot_api/api_module.py b/kdb-bot/src/bot_api/api_module.py similarity index 100% rename from src/bot_api/api_module.py rename to kdb-bot/src/bot_api/api_module.py diff --git a/src/bot_api/api_thread.py b/kdb-bot/src/bot_api/api_thread.py similarity index 100% rename from src/bot_api/api_thread.py rename to kdb-bot/src/bot_api/api_thread.py diff --git a/src/bot_api/bot-api.json b/kdb-bot/src/bot_api/bot-api.json similarity index 100% rename from src/bot_api/bot-api.json rename to kdb-bot/src/bot_api/bot-api.json diff --git a/src/bot_api/config/apisettings.development.json b/kdb-bot/src/bot_api/config/apisettings.development.json similarity index 100% rename from src/bot_api/config/apisettings.development.json rename to kdb-bot/src/bot_api/config/apisettings.development.json diff --git a/src/bot_api/config/apisettings.edrafts-lapi.json b/kdb-bot/src/bot_api/config/apisettings.edrafts-lapi.json similarity index 100% rename from src/bot_api/config/apisettings.edrafts-lapi.json rename to kdb-bot/src/bot_api/config/apisettings.edrafts-lapi.json diff --git a/src/bot_api/config/apisettings.edrafts-pc-ubuntu.json b/kdb-bot/src/bot_api/config/apisettings.edrafts-pc-ubuntu.json similarity index 100% rename from src/bot_api/config/apisettings.edrafts-pc-ubuntu.json rename to kdb-bot/src/bot_api/config/apisettings.edrafts-pc-ubuntu.json diff --git a/src/bot_api/config/apisettings.json b/kdb-bot/src/bot_api/config/apisettings.json similarity index 100% rename from src/bot_api/config/apisettings.json rename to kdb-bot/src/bot_api/config/apisettings.json diff --git a/src/bot_api/config/apisettings.production.json b/kdb-bot/src/bot_api/config/apisettings.production.json similarity index 100% rename from src/bot_api/config/apisettings.production.json rename to kdb-bot/src/bot_api/config/apisettings.production.json diff --git a/src/bot_api/config/apisettings.staging.json b/kdb-bot/src/bot_api/config/apisettings.staging.json similarity index 100% rename from src/bot_api/config/apisettings.staging.json rename to kdb-bot/src/bot_api/config/apisettings.staging.json diff --git a/src/bot_api/config/appsettings.PC-Nick.json b/kdb-bot/src/bot_api/config/appsettings.PC-Nick.json similarity index 100% rename from src/bot_api/config/appsettings.PC-Nick.json rename to kdb-bot/src/bot_api/config/appsettings.PC-Nick.json diff --git a/src/bot_api/configuration/__init__.py b/kdb-bot/src/bot_api/configuration/__init__.py similarity index 100% rename from src/bot_api/configuration/__init__.py rename to kdb-bot/src/bot_api/configuration/__init__.py diff --git a/src/bot_api/configuration/api_settings.py b/kdb-bot/src/bot_api/configuration/api_settings.py similarity index 100% rename from src/bot_api/configuration/api_settings.py rename to kdb-bot/src/bot_api/configuration/api_settings.py diff --git a/src/bot_api/configuration/authentication_settings.py b/kdb-bot/src/bot_api/configuration/authentication_settings.py similarity index 100% rename from src/bot_api/configuration/authentication_settings.py rename to kdb-bot/src/bot_api/configuration/authentication_settings.py diff --git a/src/bot_api/configuration/frontend_settings.py b/kdb-bot/src/bot_api/configuration/frontend_settings.py similarity index 100% rename from src/bot_api/configuration/frontend_settings.py rename to kdb-bot/src/bot_api/configuration/frontend_settings.py diff --git a/src/bot_api/configuration/version_settings.py b/kdb-bot/src/bot_api/configuration/version_settings.py similarity index 100% rename from src/bot_api/configuration/version_settings.py rename to kdb-bot/src/bot_api/configuration/version_settings.py diff --git a/src/bot_api/controller/__init__.py b/kdb-bot/src/bot_api/controller/__init__.py similarity index 100% rename from src/bot_api/controller/__init__.py rename to kdb-bot/src/bot_api/controller/__init__.py diff --git a/src/bot_api/controller/auth_controller.py b/kdb-bot/src/bot_api/controller/auth_controller.py similarity index 100% rename from src/bot_api/controller/auth_controller.py rename to kdb-bot/src/bot_api/controller/auth_controller.py diff --git a/src/bot_api/controller/gui_controller.py b/kdb-bot/src/bot_api/controller/gui_controller.py similarity index 100% rename from src/bot_api/controller/gui_controller.py rename to kdb-bot/src/bot_api/controller/gui_controller.py diff --git a/src/bot_api/exception/__init__.py b/kdb-bot/src/bot_api/exception/__init__.py similarity index 100% rename from src/bot_api/exception/__init__.py rename to kdb-bot/src/bot_api/exception/__init__.py diff --git a/src/bot_api/exception/service_error_code_enum.py b/kdb-bot/src/bot_api/exception/service_error_code_enum.py similarity index 100% rename from src/bot_api/exception/service_error_code_enum.py rename to kdb-bot/src/bot_api/exception/service_error_code_enum.py diff --git a/src/bot_api/exception/service_exception.py b/kdb-bot/src/bot_api/exception/service_exception.py similarity index 100% rename from src/bot_api/exception/service_exception.py rename to kdb-bot/src/bot_api/exception/service_exception.py diff --git a/src/bot_api/filter/__init__.py b/kdb-bot/src/bot_api/filter/__init__.py similarity index 100% rename from src/bot_api/filter/__init__.py rename to kdb-bot/src/bot_api/filter/__init__.py diff --git a/src/bot_api/filter/auth_user_select_criteria.py b/kdb-bot/src/bot_api/filter/auth_user_select_criteria.py similarity index 100% rename from src/bot_api/filter/auth_user_select_criteria.py rename to kdb-bot/src/bot_api/filter/auth_user_select_criteria.py diff --git a/src/bot_api/json_processor.py b/kdb-bot/src/bot_api/json_processor.py similarity index 100% rename from src/bot_api/json_processor.py rename to kdb-bot/src/bot_api/json_processor.py diff --git a/src/bot_api/logging/__init__.py b/kdb-bot/src/bot_api/logging/__init__.py similarity index 100% rename from src/bot_api/logging/__init__.py rename to kdb-bot/src/bot_api/logging/__init__.py diff --git a/src/bot_api/logging/api_logger.py b/kdb-bot/src/bot_api/logging/api_logger.py similarity index 100% rename from src/bot_api/logging/api_logger.py rename to kdb-bot/src/bot_api/logging/api_logger.py diff --git a/src/bot_api/model/__init__.py b/kdb-bot/src/bot_api/model/__init__.py similarity index 100% rename from src/bot_api/model/__init__.py rename to kdb-bot/src/bot_api/model/__init__.py diff --git a/src/bot_api/model/auth_user_dto.py b/kdb-bot/src/bot_api/model/auth_user_dto.py similarity index 100% rename from src/bot_api/model/auth_user_dto.py rename to kdb-bot/src/bot_api/model/auth_user_dto.py diff --git a/src/bot_api/model/auth_user_filtered_result_dto.py b/kdb-bot/src/bot_api/model/auth_user_filtered_result_dto.py similarity index 100% rename from src/bot_api/model/auth_user_filtered_result_dto.py rename to kdb-bot/src/bot_api/model/auth_user_filtered_result_dto.py diff --git a/src/bot_api/model/email_string_dto.py b/kdb-bot/src/bot_api/model/email_string_dto.py similarity index 100% rename from src/bot_api/model/email_string_dto.py rename to kdb-bot/src/bot_api/model/email_string_dto.py diff --git a/src/bot_api/model/error_dto.py b/kdb-bot/src/bot_api/model/error_dto.py similarity index 100% rename from src/bot_api/model/error_dto.py rename to kdb-bot/src/bot_api/model/error_dto.py diff --git a/src/bot_api/model/reset_password_dto.py b/kdb-bot/src/bot_api/model/reset_password_dto.py similarity index 100% rename from src/bot_api/model/reset_password_dto.py rename to kdb-bot/src/bot_api/model/reset_password_dto.py diff --git a/src/bot_api/model/settings_dto.py b/kdb-bot/src/bot_api/model/settings_dto.py similarity index 100% rename from src/bot_api/model/settings_dto.py rename to kdb-bot/src/bot_api/model/settings_dto.py diff --git a/src/bot_api/model/token_dto.py b/kdb-bot/src/bot_api/model/token_dto.py similarity index 100% rename from src/bot_api/model/token_dto.py rename to kdb-bot/src/bot_api/model/token_dto.py diff --git a/src/bot_api/model/update_auth_user_dto.py b/kdb-bot/src/bot_api/model/update_auth_user_dto.py similarity index 100% rename from src/bot_api/model/update_auth_user_dto.py rename to kdb-bot/src/bot_api/model/update_auth_user_dto.py diff --git a/src/bot_api/model/version_dto.py b/kdb-bot/src/bot_api/model/version_dto.py similarity index 100% rename from src/bot_api/model/version_dto.py rename to kdb-bot/src/bot_api/model/version_dto.py diff --git a/src/bot_api/route/__init__.py b/kdb-bot/src/bot_api/route/__init__.py similarity index 100% rename from src/bot_api/route/__init__.py rename to kdb-bot/src/bot_api/route/__init__.py diff --git a/src/bot_api/route/route.py b/kdb-bot/src/bot_api/route/route.py similarity index 100% rename from src/bot_api/route/route.py rename to kdb-bot/src/bot_api/route/route.py diff --git a/src/bot_api/service/__init__.py b/kdb-bot/src/bot_api/service/__init__.py similarity index 100% rename from src/bot_api/service/__init__.py rename to kdb-bot/src/bot_api/service/__init__.py diff --git a/src/bot_api/service/auth_service.py b/kdb-bot/src/bot_api/service/auth_service.py similarity index 100% rename from src/bot_api/service/auth_service.py rename to kdb-bot/src/bot_api/service/auth_service.py diff --git a/src/bot_api/transformer/__init__.py b/kdb-bot/src/bot_api/transformer/__init__.py similarity index 100% rename from src/bot_api/transformer/__init__.py rename to kdb-bot/src/bot_api/transformer/__init__.py diff --git a/src/bot_api/transformer/auth_user_transformer.py b/kdb-bot/src/bot_api/transformer/auth_user_transformer.py similarity index 100% rename from src/bot_api/transformer/auth_user_transformer.py rename to kdb-bot/src/bot_api/transformer/auth_user_transformer.py diff --git a/src/bot_core/__init__.py b/kdb-bot/src/bot_core/__init__.py similarity index 100% rename from src/bot_core/__init__.py rename to kdb-bot/src/bot_core/__init__.py diff --git a/src/bot_core/abc/__init__.py b/kdb-bot/src/bot_core/abc/__init__.py similarity index 100% rename from src/bot_core/abc/__init__.py rename to kdb-bot/src/bot_core/abc/__init__.py diff --git a/src/bot_core/abc/client_utils_service_abc.py b/kdb-bot/src/bot_core/abc/client_utils_service_abc.py similarity index 100% rename from src/bot_core/abc/client_utils_service_abc.py rename to kdb-bot/src/bot_core/abc/client_utils_service_abc.py diff --git a/src/bot_core/abc/custom_file_logger_abc.py b/kdb-bot/src/bot_core/abc/custom_file_logger_abc.py similarity index 100% rename from src/bot_core/abc/custom_file_logger_abc.py rename to kdb-bot/src/bot_core/abc/custom_file_logger_abc.py diff --git a/src/bot_core/abc/message_service_abc.py b/kdb-bot/src/bot_core/abc/message_service_abc.py similarity index 100% rename from src/bot_core/abc/message_service_abc.py rename to kdb-bot/src/bot_core/abc/message_service_abc.py diff --git a/src/bot_core/abc/module_abc.py b/kdb-bot/src/bot_core/abc/module_abc.py similarity index 100% rename from src/bot_core/abc/module_abc.py rename to kdb-bot/src/bot_core/abc/module_abc.py diff --git a/src/bot_core/bot-core.json b/kdb-bot/src/bot_core/bot-core.json similarity index 100% rename from src/bot_core/bot-core.json rename to kdb-bot/src/bot_core/bot-core.json diff --git a/src/bot_core/configuration/__init__.py b/kdb-bot/src/bot_core/configuration/__init__.py similarity index 100% rename from src/bot_core/configuration/__init__.py rename to kdb-bot/src/bot_core/configuration/__init__.py diff --git a/src/bot_core/configuration/bot_logging_settings.py b/kdb-bot/src/bot_core/configuration/bot_logging_settings.py similarity index 100% rename from src/bot_core/configuration/bot_logging_settings.py rename to kdb-bot/src/bot_core/configuration/bot_logging_settings.py diff --git a/src/bot_core/configuration/bot_settings.py b/kdb-bot/src/bot_core/configuration/bot_settings.py similarity index 100% rename from src/bot_core/configuration/bot_settings.py rename to kdb-bot/src/bot_core/configuration/bot_settings.py diff --git a/src/bot_core/configuration/feature_flags_enum.py b/kdb-bot/src/bot_core/configuration/feature_flags_enum.py similarity index 100% rename from src/bot_core/configuration/feature_flags_enum.py rename to kdb-bot/src/bot_core/configuration/feature_flags_enum.py diff --git a/src/bot_core/configuration/feature_flags_settings.py b/kdb-bot/src/bot_core/configuration/feature_flags_settings.py similarity index 100% rename from src/bot_core/configuration/feature_flags_settings.py rename to kdb-bot/src/bot_core/configuration/feature_flags_settings.py diff --git a/src/bot_core/configuration/file_logging_settings.py b/kdb-bot/src/bot_core/configuration/file_logging_settings.py similarity index 100% rename from src/bot_core/configuration/file_logging_settings.py rename to kdb-bot/src/bot_core/configuration/file_logging_settings.py diff --git a/src/bot_core/configuration/server_settings.py b/kdb-bot/src/bot_core/configuration/server_settings.py similarity index 100% rename from src/bot_core/configuration/server_settings.py rename to kdb-bot/src/bot_core/configuration/server_settings.py diff --git a/src/bot_core/core_extension/__init__.py b/kdb-bot/src/bot_core/core_extension/__init__.py similarity index 100% rename from src/bot_core/core_extension/__init__.py rename to kdb-bot/src/bot_core/core_extension/__init__.py diff --git a/src/bot_core/core_extension/core_extension_module.py b/kdb-bot/src/bot_core/core_extension/core_extension_module.py similarity index 100% rename from src/bot_core/core_extension/core_extension_module.py rename to kdb-bot/src/bot_core/core_extension/core_extension_module.py diff --git a/src/bot_core/core_extension/core_extension_on_ready_event.py b/kdb-bot/src/bot_core/core_extension/core_extension_on_ready_event.py similarity index 100% rename from src/bot_core/core_extension/core_extension_on_ready_event.py rename to kdb-bot/src/bot_core/core_extension/core_extension_on_ready_event.py diff --git a/src/bot_core/core_module.py b/kdb-bot/src/bot_core/core_module.py similarity index 100% rename from src/bot_core/core_module.py rename to kdb-bot/src/bot_core/core_module.py diff --git a/src/bot_core/events/__init__.py b/kdb-bot/src/bot_core/events/__init__.py similarity index 100% rename from src/bot_core/events/__init__.py rename to kdb-bot/src/bot_core/events/__init__.py diff --git a/src/bot_core/events/core_on_ready_event.py b/kdb-bot/src/bot_core/events/core_on_ready_event.py similarity index 100% rename from src/bot_core/events/core_on_ready_event.py rename to kdb-bot/src/bot_core/events/core_on_ready_event.py diff --git a/src/bot_core/helper/__init__.py b/kdb-bot/src/bot_core/helper/__init__.py similarity index 100% rename from src/bot_core/helper/__init__.py rename to kdb-bot/src/bot_core/helper/__init__.py diff --git a/src/bot_core/helper/log_message_helper.py b/kdb-bot/src/bot_core/helper/log_message_helper.py similarity index 100% rename from src/bot_core/helper/log_message_helper.py rename to kdb-bot/src/bot_core/helper/log_message_helper.py diff --git a/src/bot_core/logging/__init__.py b/kdb-bot/src/bot_core/logging/__init__.py similarity index 100% rename from src/bot_core/logging/__init__.py rename to kdb-bot/src/bot_core/logging/__init__.py diff --git a/src/bot_core/logging/command_logger.py b/kdb-bot/src/bot_core/logging/command_logger.py similarity index 100% rename from src/bot_core/logging/command_logger.py rename to kdb-bot/src/bot_core/logging/command_logger.py diff --git a/src/bot_core/logging/database_logger.py b/kdb-bot/src/bot_core/logging/database_logger.py similarity index 100% rename from src/bot_core/logging/database_logger.py rename to kdb-bot/src/bot_core/logging/database_logger.py diff --git a/src/bot_core/logging/message_logger.py b/kdb-bot/src/bot_core/logging/message_logger.py similarity index 100% rename from src/bot_core/logging/message_logger.py rename to kdb-bot/src/bot_core/logging/message_logger.py diff --git a/src/bot_core/pipes/__init__.py b/kdb-bot/src/bot_core/pipes/__init__.py similarity index 100% rename from src/bot_core/pipes/__init__.py rename to kdb-bot/src/bot_core/pipes/__init__.py diff --git a/src/bot_core/pipes/date_time_offset_pipe.py b/kdb-bot/src/bot_core/pipes/date_time_offset_pipe.py similarity index 100% rename from src/bot_core/pipes/date_time_offset_pipe.py rename to kdb-bot/src/bot_core/pipes/date_time_offset_pipe.py diff --git a/src/bot_core/service/__init__.py b/kdb-bot/src/bot_core/service/__init__.py similarity index 100% rename from src/bot_core/service/__init__.py rename to kdb-bot/src/bot_core/service/__init__.py diff --git a/src/bot_core/service/client_utils_service.py b/kdb-bot/src/bot_core/service/client_utils_service.py similarity index 100% rename from src/bot_core/service/client_utils_service.py rename to kdb-bot/src/bot_core/service/client_utils_service.py diff --git a/src/bot_core/service/message_service.py b/kdb-bot/src/bot_core/service/message_service.py similarity index 100% rename from src/bot_core/service/message_service.py rename to kdb-bot/src/bot_core/service/message_service.py diff --git a/src/bot_data/__init__.py b/kdb-bot/src/bot_data/__init__.py similarity index 100% rename from src/bot_data/__init__.py rename to kdb-bot/src/bot_data/__init__.py diff --git a/src/bot_data/abc/__init__.py b/kdb-bot/src/bot_data/abc/__init__.py similarity index 100% rename from src/bot_data/abc/__init__.py rename to kdb-bot/src/bot_data/abc/__init__.py diff --git a/src/bot_data/abc/auth_user_repository_abc.py b/kdb-bot/src/bot_data/abc/auth_user_repository_abc.py similarity index 100% rename from src/bot_data/abc/auth_user_repository_abc.py rename to kdb-bot/src/bot_data/abc/auth_user_repository_abc.py diff --git a/src/bot_data/abc/auto_role_repository_abc.py b/kdb-bot/src/bot_data/abc/auto_role_repository_abc.py similarity index 100% rename from src/bot_data/abc/auto_role_repository_abc.py rename to kdb-bot/src/bot_data/abc/auto_role_repository_abc.py diff --git a/src/bot_data/abc/client_repository_abc.py b/kdb-bot/src/bot_data/abc/client_repository_abc.py similarity index 100% rename from src/bot_data/abc/client_repository_abc.py rename to kdb-bot/src/bot_data/abc/client_repository_abc.py diff --git a/src/bot_data/abc/known_user_repository_abc.py b/kdb-bot/src/bot_data/abc/known_user_repository_abc.py similarity index 100% rename from src/bot_data/abc/known_user_repository_abc.py rename to kdb-bot/src/bot_data/abc/known_user_repository_abc.py diff --git a/src/bot_data/abc/migration_abc.py b/kdb-bot/src/bot_data/abc/migration_abc.py similarity index 100% rename from src/bot_data/abc/migration_abc.py rename to kdb-bot/src/bot_data/abc/migration_abc.py diff --git a/src/bot_data/abc/server_repository_abc.py b/kdb-bot/src/bot_data/abc/server_repository_abc.py similarity index 100% rename from src/bot_data/abc/server_repository_abc.py rename to kdb-bot/src/bot_data/abc/server_repository_abc.py diff --git a/src/bot_data/abc/user_joined_server_repository_abc.py b/kdb-bot/src/bot_data/abc/user_joined_server_repository_abc.py similarity index 100% rename from src/bot_data/abc/user_joined_server_repository_abc.py rename to kdb-bot/src/bot_data/abc/user_joined_server_repository_abc.py diff --git a/src/bot_data/abc/user_joined_voice_channel_abc.py b/kdb-bot/src/bot_data/abc/user_joined_voice_channel_abc.py similarity index 100% rename from src/bot_data/abc/user_joined_voice_channel_abc.py rename to kdb-bot/src/bot_data/abc/user_joined_voice_channel_abc.py diff --git a/src/bot_data/abc/user_repository_abc.py b/kdb-bot/src/bot_data/abc/user_repository_abc.py similarity index 100% rename from src/bot_data/abc/user_repository_abc.py rename to kdb-bot/src/bot_data/abc/user_repository_abc.py diff --git a/src/bot_data/bot-data.json b/kdb-bot/src/bot_data/bot-data.json similarity index 100% rename from src/bot_data/bot-data.json rename to kdb-bot/src/bot_data/bot-data.json diff --git a/src/bot_data/data_module.py b/kdb-bot/src/bot_data/data_module.py similarity index 100% rename from src/bot_data/data_module.py rename to kdb-bot/src/bot_data/data_module.py diff --git a/src/bot_data/db_context.py b/kdb-bot/src/bot_data/db_context.py similarity index 100% rename from src/bot_data/db_context.py rename to kdb-bot/src/bot_data/db_context.py diff --git a/src/bot_data/filtered_result.py b/kdb-bot/src/bot_data/filtered_result.py similarity index 100% rename from src/bot_data/filtered_result.py rename to kdb-bot/src/bot_data/filtered_result.py diff --git a/src/bot_data/migration/__init__.py b/kdb-bot/src/bot_data/migration/__init__.py similarity index 100% rename from src/bot_data/migration/__init__.py rename to kdb-bot/src/bot_data/migration/__init__.py diff --git a/src/bot_data/migration/api_migration.py b/kdb-bot/src/bot_data/migration/api_migration.py similarity index 100% rename from src/bot_data/migration/api_migration.py rename to kdb-bot/src/bot_data/migration/api_migration.py diff --git a/src/bot_data/migration/auto_role_migration.py b/kdb-bot/src/bot_data/migration/auto_role_migration.py similarity index 100% rename from src/bot_data/migration/auto_role_migration.py rename to kdb-bot/src/bot_data/migration/auto_role_migration.py diff --git a/src/bot_data/migration/initial_migration.py b/kdb-bot/src/bot_data/migration/initial_migration.py similarity index 100% rename from src/bot_data/migration/initial_migration.py rename to kdb-bot/src/bot_data/migration/initial_migration.py diff --git a/src/bot_data/model/__init__.py b/kdb-bot/src/bot_data/model/__init__.py similarity index 100% rename from src/bot_data/model/__init__.py rename to kdb-bot/src/bot_data/model/__init__.py diff --git a/src/bot_data/model/auth_role_enum.py b/kdb-bot/src/bot_data/model/auth_role_enum.py similarity index 100% rename from src/bot_data/model/auth_role_enum.py rename to kdb-bot/src/bot_data/model/auth_role_enum.py diff --git a/src/bot_data/model/auth_user.py b/kdb-bot/src/bot_data/model/auth_user.py similarity index 100% rename from src/bot_data/model/auth_user.py rename to kdb-bot/src/bot_data/model/auth_user.py diff --git a/src/bot_data/model/auto_role.py b/kdb-bot/src/bot_data/model/auto_role.py similarity index 100% rename from src/bot_data/model/auto_role.py rename to kdb-bot/src/bot_data/model/auto_role.py diff --git a/src/bot_data/model/auto_role_rule.py b/kdb-bot/src/bot_data/model/auto_role_rule.py similarity index 100% rename from src/bot_data/model/auto_role_rule.py rename to kdb-bot/src/bot_data/model/auto_role_rule.py diff --git a/src/bot_data/model/client.py b/kdb-bot/src/bot_data/model/client.py similarity index 100% rename from src/bot_data/model/client.py rename to kdb-bot/src/bot_data/model/client.py diff --git a/src/bot_data/model/known_user.py b/kdb-bot/src/bot_data/model/known_user.py similarity index 100% rename from src/bot_data/model/known_user.py rename to kdb-bot/src/bot_data/model/known_user.py diff --git a/src/bot_data/model/migration_history.py b/kdb-bot/src/bot_data/model/migration_history.py similarity index 100% rename from src/bot_data/model/migration_history.py rename to kdb-bot/src/bot_data/model/migration_history.py diff --git a/src/bot_data/model/server.py b/kdb-bot/src/bot_data/model/server.py similarity index 100% rename from src/bot_data/model/server.py rename to kdb-bot/src/bot_data/model/server.py diff --git a/src/bot_data/model/user.py b/kdb-bot/src/bot_data/model/user.py similarity index 100% rename from src/bot_data/model/user.py rename to kdb-bot/src/bot_data/model/user.py diff --git a/src/bot_data/model/user_joined_server.py b/kdb-bot/src/bot_data/model/user_joined_server.py similarity index 100% rename from src/bot_data/model/user_joined_server.py rename to kdb-bot/src/bot_data/model/user_joined_server.py diff --git a/src/bot_data/model/user_joined_voice_channel.py b/kdb-bot/src/bot_data/model/user_joined_voice_channel.py similarity index 100% rename from src/bot_data/model/user_joined_voice_channel.py rename to kdb-bot/src/bot_data/model/user_joined_voice_channel.py diff --git a/src/bot_data/service/__init__.py b/kdb-bot/src/bot_data/service/__init__.py similarity index 100% rename from src/bot_data/service/__init__.py rename to kdb-bot/src/bot_data/service/__init__.py diff --git a/src/bot_data/service/auth_user_repository_service.py b/kdb-bot/src/bot_data/service/auth_user_repository_service.py similarity index 100% rename from src/bot_data/service/auth_user_repository_service.py rename to kdb-bot/src/bot_data/service/auth_user_repository_service.py diff --git a/src/bot_data/service/auto_role_repository_service.py b/kdb-bot/src/bot_data/service/auto_role_repository_service.py similarity index 100% rename from src/bot_data/service/auto_role_repository_service.py rename to kdb-bot/src/bot_data/service/auto_role_repository_service.py diff --git a/src/bot_data/service/client_repository_service.py b/kdb-bot/src/bot_data/service/client_repository_service.py similarity index 100% rename from src/bot_data/service/client_repository_service.py rename to kdb-bot/src/bot_data/service/client_repository_service.py diff --git a/src/bot_data/service/known_user_repository_service.py b/kdb-bot/src/bot_data/service/known_user_repository_service.py similarity index 100% rename from src/bot_data/service/known_user_repository_service.py rename to kdb-bot/src/bot_data/service/known_user_repository_service.py diff --git a/src/bot_data/service/migration_service.py b/kdb-bot/src/bot_data/service/migration_service.py similarity index 100% rename from src/bot_data/service/migration_service.py rename to kdb-bot/src/bot_data/service/migration_service.py diff --git a/src/bot_data/service/server_repository_service.py b/kdb-bot/src/bot_data/service/server_repository_service.py similarity index 100% rename from src/bot_data/service/server_repository_service.py rename to kdb-bot/src/bot_data/service/server_repository_service.py diff --git a/src/bot_data/service/user_joined_server_repository_service.py b/kdb-bot/src/bot_data/service/user_joined_server_repository_service.py similarity index 100% rename from src/bot_data/service/user_joined_server_repository_service.py rename to kdb-bot/src/bot_data/service/user_joined_server_repository_service.py diff --git a/src/bot_data/service/user_joined_voice_channel_service.py b/kdb-bot/src/bot_data/service/user_joined_voice_channel_service.py similarity index 100% rename from src/bot_data/service/user_joined_voice_channel_service.py rename to kdb-bot/src/bot_data/service/user_joined_voice_channel_service.py diff --git a/src/bot_data/service/user_repository_service.py b/kdb-bot/src/bot_data/service/user_repository_service.py similarity index 100% rename from src/bot_data/service/user_repository_service.py rename to kdb-bot/src/bot_data/service/user_repository_service.py diff --git a/src/modules/__init__.py b/kdb-bot/src/modules/__init__.py similarity index 100% rename from src/modules/__init__.py rename to kdb-bot/src/modules/__init__.py diff --git a/src/modules/admin/__init__.py b/kdb-bot/src/modules/admin/__init__.py similarity index 100% rename from src/modules/admin/__init__.py rename to kdb-bot/src/modules/admin/__init__.py diff --git a/src/modules/admin/admin.json b/kdb-bot/src/modules/admin/admin.json similarity index 100% rename from src/modules/admin/admin.json rename to kdb-bot/src/modules/admin/admin.json diff --git a/src/modules/admin/admin_module.py b/kdb-bot/src/modules/admin/admin_module.py similarity index 100% rename from src/modules/admin/admin_module.py rename to kdb-bot/src/modules/admin/admin_module.py diff --git a/src/modules/admin/command/__init__.py b/kdb-bot/src/modules/admin/command/__init__.py similarity index 100% rename from src/modules/admin/command/__init__.py rename to kdb-bot/src/modules/admin/command/__init__.py diff --git a/src/modules/admin/command/restart_command.py b/kdb-bot/src/modules/admin/command/restart_command.py similarity index 100% rename from src/modules/admin/command/restart_command.py rename to kdb-bot/src/modules/admin/command/restart_command.py diff --git a/src/modules/admin/command/shutdown_command.py b/kdb-bot/src/modules/admin/command/shutdown_command.py similarity index 100% rename from src/modules/admin/command/shutdown_command.py rename to kdb-bot/src/modules/admin/command/shutdown_command.py diff --git a/src/modules/auto_role/__init__.py b/kdb-bot/src/modules/auto_role/__init__.py similarity index 100% rename from src/modules/auto_role/__init__.py rename to kdb-bot/src/modules/auto_role/__init__.py diff --git a/src/modules/auto_role/auto-role.json b/kdb-bot/src/modules/auto_role/auto-role.json similarity index 100% rename from src/modules/auto_role/auto-role.json rename to kdb-bot/src/modules/auto_role/auto-role.json diff --git a/src/modules/auto_role/auto_role_module.py b/kdb-bot/src/modules/auto_role/auto_role_module.py similarity index 100% rename from src/modules/auto_role/auto_role_module.py rename to kdb-bot/src/modules/auto_role/auto_role_module.py diff --git a/src/modules/auto_role/command/__init__.py b/kdb-bot/src/modules/auto_role/command/__init__.py similarity index 100% rename from src/modules/auto_role/command/__init__.py rename to kdb-bot/src/modules/auto_role/command/__init__.py diff --git a/src/modules/auto_role/command/auto_role_group.py b/kdb-bot/src/modules/auto_role/command/auto_role_group.py similarity index 100% rename from src/modules/auto_role/command/auto_role_group.py rename to kdb-bot/src/modules/auto_role/command/auto_role_group.py diff --git a/src/modules/auto_role/events/__init__.py b/kdb-bot/src/modules/auto_role/events/__init__.py similarity index 100% rename from src/modules/auto_role/events/__init__.py rename to kdb-bot/src/modules/auto_role/events/__init__.py diff --git a/src/modules/auto_role/events/auto_role_on_raw_reaction_add.py b/kdb-bot/src/modules/auto_role/events/auto_role_on_raw_reaction_add.py similarity index 100% rename from src/modules/auto_role/events/auto_role_on_raw_reaction_add.py rename to kdb-bot/src/modules/auto_role/events/auto_role_on_raw_reaction_add.py diff --git a/src/modules/auto_role/events/auto_role_on_raw_reaction_remove.py b/kdb-bot/src/modules/auto_role/events/auto_role_on_raw_reaction_remove.py similarity index 100% rename from src/modules/auto_role/events/auto_role_on_raw_reaction_remove.py rename to kdb-bot/src/modules/auto_role/events/auto_role_on_raw_reaction_remove.py diff --git a/src/modules/auto_role/helper/__init__.py b/kdb-bot/src/modules/auto_role/helper/__init__.py similarity index 100% rename from src/modules/auto_role/helper/__init__.py rename to kdb-bot/src/modules/auto_role/helper/__init__.py diff --git a/src/modules/auto_role/helper/reaction_handler.py b/kdb-bot/src/modules/auto_role/helper/reaction_handler.py similarity index 100% rename from src/modules/auto_role/helper/reaction_handler.py rename to kdb-bot/src/modules/auto_role/helper/reaction_handler.py diff --git a/src/modules/base/__init__.py b/kdb-bot/src/modules/base/__init__.py similarity index 100% rename from src/modules/base/__init__.py rename to kdb-bot/src/modules/base/__init__.py diff --git a/src/modules/base/abc/__init__.py b/kdb-bot/src/modules/base/abc/__init__.py similarity index 100% rename from src/modules/base/abc/__init__.py rename to kdb-bot/src/modules/base/abc/__init__.py diff --git a/src/modules/base/abc/base_helper_abc.py b/kdb-bot/src/modules/base/abc/base_helper_abc.py similarity index 100% rename from src/modules/base/abc/base_helper_abc.py rename to kdb-bot/src/modules/base/abc/base_helper_abc.py diff --git a/src/modules/base/base.json b/kdb-bot/src/modules/base/base.json similarity index 100% rename from src/modules/base/base.json rename to kdb-bot/src/modules/base/base.json diff --git a/src/modules/base/base_module.py b/kdb-bot/src/modules/base/base_module.py similarity index 100% rename from src/modules/base/base_module.py rename to kdb-bot/src/modules/base/base_module.py diff --git a/src/modules/base/command/__init__.py b/kdb-bot/src/modules/base/command/__init__.py similarity index 100% rename from src/modules/base/command/__init__.py rename to kdb-bot/src/modules/base/command/__init__.py diff --git a/src/modules/base/command/afk_command.py b/kdb-bot/src/modules/base/command/afk_command.py similarity index 100% rename from src/modules/base/command/afk_command.py rename to kdb-bot/src/modules/base/command/afk_command.py diff --git a/src/modules/base/command/help_command.py b/kdb-bot/src/modules/base/command/help_command.py similarity index 100% rename from src/modules/base/command/help_command.py rename to kdb-bot/src/modules/base/command/help_command.py diff --git a/src/modules/base/command/info_command.py b/kdb-bot/src/modules/base/command/info_command.py similarity index 100% rename from src/modules/base/command/info_command.py rename to kdb-bot/src/modules/base/command/info_command.py diff --git a/src/modules/base/command/ping_command.py b/kdb-bot/src/modules/base/command/ping_command.py similarity index 100% rename from src/modules/base/command/ping_command.py rename to kdb-bot/src/modules/base/command/ping_command.py diff --git a/src/modules/base/configuration/__init__.py b/kdb-bot/src/modules/base/configuration/__init__.py similarity index 100% rename from src/modules/base/configuration/__init__.py rename to kdb-bot/src/modules/base/configuration/__init__.py diff --git a/src/modules/base/configuration/base_server_settings.py b/kdb-bot/src/modules/base/configuration/base_server_settings.py similarity index 100% rename from src/modules/base/configuration/base_server_settings.py rename to kdb-bot/src/modules/base/configuration/base_server_settings.py diff --git a/src/modules/base/configuration/base_settings.py b/kdb-bot/src/modules/base/configuration/base_settings.py similarity index 100% rename from src/modules/base/configuration/base_settings.py rename to kdb-bot/src/modules/base/configuration/base_settings.py diff --git a/src/modules/base/events/__init__.py b/kdb-bot/src/modules/base/events/__init__.py similarity index 100% rename from src/modules/base/events/__init__.py rename to kdb-bot/src/modules/base/events/__init__.py diff --git a/src/modules/base/events/base_on_command_error_event.py b/kdb-bot/src/modules/base/events/base_on_command_error_event.py similarity index 100% rename from src/modules/base/events/base_on_command_error_event.py rename to kdb-bot/src/modules/base/events/base_on_command_error_event.py diff --git a/src/modules/base/events/base_on_command_event.py b/kdb-bot/src/modules/base/events/base_on_command_event.py similarity index 100% rename from src/modules/base/events/base_on_command_event.py rename to kdb-bot/src/modules/base/events/base_on_command_event.py diff --git a/src/modules/base/events/base_on_member_join_event.py b/kdb-bot/src/modules/base/events/base_on_member_join_event.py similarity index 100% rename from src/modules/base/events/base_on_member_join_event.py rename to kdb-bot/src/modules/base/events/base_on_member_join_event.py diff --git a/src/modules/base/events/base_on_member_remove_event.py b/kdb-bot/src/modules/base/events/base_on_member_remove_event.py similarity index 100% rename from src/modules/base/events/base_on_member_remove_event.py rename to kdb-bot/src/modules/base/events/base_on_member_remove_event.py diff --git a/src/modules/base/events/base_on_message_event.py b/kdb-bot/src/modules/base/events/base_on_message_event.py similarity index 100% rename from src/modules/base/events/base_on_message_event.py rename to kdb-bot/src/modules/base/events/base_on_message_event.py diff --git a/src/modules/base/events/base_on_voice_state_update_event.py b/kdb-bot/src/modules/base/events/base_on_voice_state_update_event.py similarity index 100% rename from src/modules/base/events/base_on_voice_state_update_event.py rename to kdb-bot/src/modules/base/events/base_on_voice_state_update_event.py diff --git a/src/modules/base/service/__init__.py b/kdb-bot/src/modules/base/service/__init__.py similarity index 100% rename from src/modules/base/service/__init__.py rename to kdb-bot/src/modules/base/service/__init__.py diff --git a/src/modules/base/service/base_helper_service.py b/kdb-bot/src/modules/base/service/base_helper_service.py similarity index 100% rename from src/modules/base/service/base_helper_service.py rename to kdb-bot/src/modules/base/service/base_helper_service.py diff --git a/src/modules/boot_log/__init__.py b/kdb-bot/src/modules/boot_log/__init__.py similarity index 100% rename from src/modules/boot_log/__init__.py rename to kdb-bot/src/modules/boot_log/__init__.py diff --git a/src/modules/boot_log/boot-log.json b/kdb-bot/src/modules/boot_log/boot-log.json similarity index 100% rename from src/modules/boot_log/boot-log.json rename to kdb-bot/src/modules/boot_log/boot-log.json diff --git a/src/modules/boot_log/boot_log_extension.py b/kdb-bot/src/modules/boot_log/boot_log_extension.py similarity index 100% rename from src/modules/boot_log/boot_log_extension.py rename to kdb-bot/src/modules/boot_log/boot_log_extension.py diff --git a/src/modules/boot_log/boot_log_module.py b/kdb-bot/src/modules/boot_log/boot_log_module.py similarity index 100% rename from src/modules/boot_log/boot_log_module.py rename to kdb-bot/src/modules/boot_log/boot_log_module.py diff --git a/src/modules/boot_log/boot_log_on_ready_event.py b/kdb-bot/src/modules/boot_log/boot_log_on_ready_event.py similarity index 100% rename from src/modules/boot_log/boot_log_on_ready_event.py rename to kdb-bot/src/modules/boot_log/boot_log_on_ready_event.py diff --git a/src/modules/boot_log/configuration/__init__.py b/kdb-bot/src/modules/boot_log/configuration/__init__.py similarity index 100% rename from src/modules/boot_log/configuration/__init__.py rename to kdb-bot/src/modules/boot_log/configuration/__init__.py diff --git a/src/modules/boot_log/configuration/boot_log_server_settings.py b/kdb-bot/src/modules/boot_log/configuration/boot_log_server_settings.py similarity index 100% rename from src/modules/boot_log/configuration/boot_log_server_settings.py rename to kdb-bot/src/modules/boot_log/configuration/boot_log_server_settings.py diff --git a/src/modules/boot_log/configuration/boot_log_settings.py b/kdb-bot/src/modules/boot_log/configuration/boot_log_settings.py similarity index 100% rename from src/modules/boot_log/configuration/boot_log_settings.py rename to kdb-bot/src/modules/boot_log/configuration/boot_log_settings.py diff --git a/src/modules/database/__init__.py b/kdb-bot/src/modules/database/__init__.py similarity index 100% rename from src/modules/database/__init__.py rename to kdb-bot/src/modules/database/__init__.py diff --git a/src/modules/database/database.json b/kdb-bot/src/modules/database/database.json similarity index 100% rename from src/modules/database/database.json rename to kdb-bot/src/modules/database/database.json diff --git a/src/modules/database/database_extension.py b/kdb-bot/src/modules/database/database_extension.py similarity index 100% rename from src/modules/database/database_extension.py rename to kdb-bot/src/modules/database/database_extension.py diff --git a/src/modules/database/database_module.py b/kdb-bot/src/modules/database/database_module.py similarity index 100% rename from src/modules/database/database_module.py rename to kdb-bot/src/modules/database/database_module.py diff --git a/src/modules/database/database_on_ready_event.py b/kdb-bot/src/modules/database/database_on_ready_event.py similarity index 100% rename from src/modules/database/database_on_ready_event.py rename to kdb-bot/src/modules/database/database_on_ready_event.py diff --git a/src/modules/moderator/__init__.py b/kdb-bot/src/modules/moderator/__init__.py similarity index 100% rename from src/modules/moderator/__init__.py rename to kdb-bot/src/modules/moderator/__init__.py diff --git a/src/modules/moderator/command/__init__.py b/kdb-bot/src/modules/moderator/command/__init__.py similarity index 100% rename from src/modules/moderator/command/__init__.py rename to kdb-bot/src/modules/moderator/command/__init__.py diff --git a/src/modules/moderator/command/purge_command.py b/kdb-bot/src/modules/moderator/command/purge_command.py similarity index 100% rename from src/modules/moderator/command/purge_command.py rename to kdb-bot/src/modules/moderator/command/purge_command.py diff --git a/src/modules/moderator/command/user_group.py b/kdb-bot/src/modules/moderator/command/user_group.py similarity index 100% rename from src/modules/moderator/command/user_group.py rename to kdb-bot/src/modules/moderator/command/user_group.py diff --git a/src/modules/moderator/moderator.json b/kdb-bot/src/modules/moderator/moderator.json similarity index 100% rename from src/modules/moderator/moderator.json rename to kdb-bot/src/modules/moderator/moderator.json diff --git a/src/modules/moderator/moderator_module.py b/kdb-bot/src/modules/moderator/moderator_module.py similarity index 100% rename from src/modules/moderator/moderator_module.py rename to kdb-bot/src/modules/moderator/moderator_module.py diff --git a/src/modules/permission/__init__.py b/kdb-bot/src/modules/permission/__init__.py similarity index 100% rename from src/modules/permission/__init__.py rename to kdb-bot/src/modules/permission/__init__.py diff --git a/src/modules/permission/abc/__init__.py b/kdb-bot/src/modules/permission/abc/__init__.py similarity index 100% rename from src/modules/permission/abc/__init__.py rename to kdb-bot/src/modules/permission/abc/__init__.py diff --git a/src/modules/permission/abc/permission_service_abc.py b/kdb-bot/src/modules/permission/abc/permission_service_abc.py similarity index 100% rename from src/modules/permission/abc/permission_service_abc.py rename to kdb-bot/src/modules/permission/abc/permission_service_abc.py diff --git a/src/modules/permission/configuration/__init__.py b/kdb-bot/src/modules/permission/configuration/__init__.py similarity index 100% rename from src/modules/permission/configuration/__init__.py rename to kdb-bot/src/modules/permission/configuration/__init__.py diff --git a/src/modules/permission/configuration/permission_server_settings.py b/kdb-bot/src/modules/permission/configuration/permission_server_settings.py similarity index 100% rename from src/modules/permission/configuration/permission_server_settings.py rename to kdb-bot/src/modules/permission/configuration/permission_server_settings.py diff --git a/src/modules/permission/configuration/permission_settings.py b/kdb-bot/src/modules/permission/configuration/permission_settings.py similarity index 100% rename from src/modules/permission/configuration/permission_settings.py rename to kdb-bot/src/modules/permission/configuration/permission_settings.py diff --git a/src/modules/permission/events/__init__.py b/kdb-bot/src/modules/permission/events/__init__.py similarity index 100% rename from src/modules/permission/events/__init__.py rename to kdb-bot/src/modules/permission/events/__init__.py diff --git a/src/modules/permission/events/permission_on_member_update_event.py b/kdb-bot/src/modules/permission/events/permission_on_member_update_event.py similarity index 100% rename from src/modules/permission/events/permission_on_member_update_event.py rename to kdb-bot/src/modules/permission/events/permission_on_member_update_event.py diff --git a/src/modules/permission/events/permission_on_ready_event.py b/kdb-bot/src/modules/permission/events/permission_on_ready_event.py similarity index 100% rename from src/modules/permission/events/permission_on_ready_event.py rename to kdb-bot/src/modules/permission/events/permission_on_ready_event.py diff --git a/src/modules/permission/permission.json b/kdb-bot/src/modules/permission/permission.json similarity index 100% rename from src/modules/permission/permission.json rename to kdb-bot/src/modules/permission/permission.json diff --git a/src/modules/permission/permission_module.py b/kdb-bot/src/modules/permission/permission_module.py similarity index 100% rename from src/modules/permission/permission_module.py rename to kdb-bot/src/modules/permission/permission_module.py diff --git a/src/modules/permission/service/__init__.py b/kdb-bot/src/modules/permission/service/__init__.py similarity index 100% rename from src/modules/permission/service/__init__.py rename to kdb-bot/src/modules/permission/service/__init__.py diff --git a/src/modules/permission/service/permission_service.py b/kdb-bot/src/modules/permission/service/permission_service.py similarity index 100% rename from src/modules/permission/service/permission_service.py rename to kdb-bot/src/modules/permission/service/permission_service.py From 2b08c1d71e04fd001d4a6181983d932426f31599 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 15 Oct 2022 23:38:38 +0200 Subject: [PATCH 020/102] Updated bot stuff #70 --- kdb-bot/src/bot/__init__.py | 4 ++-- kdb-bot/src/bot/bot.json | 12 +++++++++--- kdb-bot/src/bot_api/__init__.py | 4 ++-- kdb-bot/src/bot_api/abc/__init__.py | 4 ++-- kdb-bot/src/bot_api/bot-api.json | 8 +------- kdb-bot/src/bot_api/configuration/__init__.py | 4 ++-- kdb-bot/src/bot_api/controller/__init__.py | 4 ++-- kdb-bot/src/bot_api/exception/__init__.py | 4 ++-- kdb-bot/src/bot_api/filter/__init__.py | 4 ++-- kdb-bot/src/bot_api/logging/__init__.py | 4 ++-- kdb-bot/src/bot_api/model/__init__.py | 4 ++-- kdb-bot/src/bot_api/route/__init__.py | 4 ++-- kdb-bot/src/bot_api/service/__init__.py | 4 ++-- kdb-bot/src/bot_api/transformer/__init__.py | 4 ++-- kdb-bot/src/bot_core/__init__.py | 4 ++-- kdb-bot/src/bot_core/abc/__init__.py | 4 ++-- kdb-bot/src/bot_core/configuration/__init__.py | 4 ++-- kdb-bot/src/bot_core/core_extension/__init__.py | 4 ++-- kdb-bot/src/bot_core/events/__init__.py | 4 ++-- kdb-bot/src/bot_core/helper/__init__.py | 4 ++-- kdb-bot/src/bot_core/logging/__init__.py | 4 ++-- kdb-bot/src/bot_core/pipes/__init__.py | 4 ++-- kdb-bot/src/bot_core/service/__init__.py | 4 ++-- kdb-bot/src/bot_data/__init__.py | 4 ++-- kdb-bot/src/bot_data/abc/__init__.py | 4 ++-- kdb-bot/src/bot_data/migration/__init__.py | 4 ++-- kdb-bot/src/bot_data/model/__init__.py | 4 ++-- kdb-bot/src/bot_data/service/__init__.py | 4 ++-- kdb-bot/src/modules/admin/__init__.py | 4 ++-- kdb-bot/src/modules/admin/command/__init__.py | 4 ++-- kdb-bot/src/modules/auto_role/__init__.py | 4 ++-- kdb-bot/src/modules/auto_role/command/__init__.py | 4 ++-- kdb-bot/src/modules/auto_role/events/__init__.py | 4 ++-- kdb-bot/src/modules/auto_role/helper/__init__.py | 4 ++-- kdb-bot/src/modules/base/__init__.py | 4 ++-- kdb-bot/src/modules/base/abc/__init__.py | 4 ++-- kdb-bot/src/modules/base/command/__init__.py | 4 ++-- kdb-bot/src/modules/base/configuration/__init__.py | 4 ++-- kdb-bot/src/modules/base/events/__init__.py | 4 ++-- kdb-bot/src/modules/base/service/__init__.py | 4 ++-- kdb-bot/src/modules/boot_log/__init__.py | 4 ++-- .../src/modules/boot_log/configuration/__init__.py | 4 ++-- kdb-bot/src/modules/database/__init__.py | 4 ++-- kdb-bot/src/modules/moderator/__init__.py | 4 ++-- kdb-bot/src/modules/moderator/command/__init__.py | 4 ++-- kdb-bot/src/modules/permission/__init__.py | 4 ++-- kdb-bot/src/modules/permission/abc/__init__.py | 4 ++-- .../src/modules/permission/configuration/__init__.py | 4 ++-- kdb-bot/src/modules/permission/events/__init__.py | 4 ++-- kdb-bot/src/modules/permission/service/__init__.py | 4 ++-- 50 files changed, 106 insertions(+), 106 deletions(-) diff --git a/kdb-bot/src/bot/__init__.py b/kdb-bot/src/bot/__init__.py index 987fa6ee8e..bec166fa4a 100644 --- a/kdb-bot/src/bot/__init__.py +++ b/kdb-bot/src/bot/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot/bot.json b/kdb-bot/src/bot/bot.json index 89afddf9af..ff36eea75d 100644 --- a/kdb-bot/src/bot/bot.json +++ b/kdb-bot/src/bot/bot.json @@ -3,8 +3,8 @@ "Name": "bot", "Version": { "Major": "0", - "Minor": "2", - "Micro": "3" + "Minor": "3", + "Micro": "0" }, "Author": "Sven Heidemann", "AuthorEmail": "sven.heidemann@sh-edraft.de", @@ -19,7 +19,13 @@ "cpl-core==2022.10.0.post6", "cpl-translation==2022.10.0.post1", "cpl-query==2022.10.0.post2", - "cpl-discord==2022.10.0.post5" + "cpl-discord==2022.10.0.post5", + "Flask==2.2.2", + "Flask[async]==2.2.2", + "Flask-Classful==0.14.2", + "Flask-Cors==3.0.10", + "PyJWT[crypto]==2.5.0", + "PyJWT==2.5.0" ], "DevDependencies": [ "cpl-cli==2022.10.0" diff --git a/kdb-bot/src/bot_api/__init__.py b/kdb-bot/src/bot_api/__init__.py index 99097c738a..6029ae84f4 100644 --- a/kdb-bot/src/bot_api/__init__.py +++ b/kdb-bot/src/bot_api/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_api' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_api/abc/__init__.py b/kdb-bot/src/bot_api/abc/__init__.py index 38bf68b7f9..25aa13fe09 100644 --- a/kdb-bot/src/bot_api/abc/__init__.py +++ b/kdb-bot/src/bot_api/abc/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_api.abc' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_api/bot-api.json b/kdb-bot/src/bot_api/bot-api.json index a807eeb181..86b1012e38 100644 --- a/kdb-bot/src/bot_api/bot-api.json +++ b/kdb-bot/src/bot_api/bot-api.json @@ -16,13 +16,7 @@ "LicenseName": "", "LicenseDescription": "", "Dependencies": [ - "cpl-core==2022.10.0.post6", - "Flask==2.2.2", - "Flask[async]==2.2.2", - "Flask-Classful==0.14.2", - "Flask-Cors==3.0.10", - "PyJWT[crypto]==2.5.0", - "PyJWT==2.5.0" + "cpl-core==2022.10.0.post6" ], "DevDependencies": [ "cpl-cli==2022.10.0" diff --git a/kdb-bot/src/bot_api/configuration/__init__.py b/kdb-bot/src/bot_api/configuration/__init__.py index 86e07283fa..823f5a2b5a 100644 --- a/kdb-bot/src/bot_api/configuration/__init__.py +++ b/kdb-bot/src/bot_api/configuration/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_api.configuration' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_api/controller/__init__.py b/kdb-bot/src/bot_api/controller/__init__.py index 44c37e5c00..e70854052b 100644 --- a/kdb-bot/src/bot_api/controller/__init__.py +++ b/kdb-bot/src/bot_api/controller/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_api.controller' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_api/exception/__init__.py b/kdb-bot/src/bot_api/exception/__init__.py index b37a52c4f5..4db4fc25be 100644 --- a/kdb-bot/src/bot_api/exception/__init__.py +++ b/kdb-bot/src/bot_api/exception/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_api.exception' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_api/filter/__init__.py b/kdb-bot/src/bot_api/filter/__init__.py index 0f9e52aa6a..0b898bd27c 100644 --- a/kdb-bot/src/bot_api/filter/__init__.py +++ b/kdb-bot/src/bot_api/filter/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_api.filter' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_api/logging/__init__.py b/kdb-bot/src/bot_api/logging/__init__.py index d7b9d180c4..7575e63361 100644 --- a/kdb-bot/src/bot_api/logging/__init__.py +++ b/kdb-bot/src/bot_api/logging/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_api.logging' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_api/model/__init__.py b/kdb-bot/src/bot_api/model/__init__.py index da73f2230b..47a3f826c7 100644 --- a/kdb-bot/src/bot_api/model/__init__.py +++ b/kdb-bot/src/bot_api/model/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_api.model' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_api/route/__init__.py b/kdb-bot/src/bot_api/route/__init__.py index 3f08538e82..7225cfad0d 100644 --- a/kdb-bot/src/bot_api/route/__init__.py +++ b/kdb-bot/src/bot_api/route/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_api.route' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_api/service/__init__.py b/kdb-bot/src/bot_api/service/__init__.py index 3a5cf24d73..1e2fd6a5b9 100644 --- a/kdb-bot/src/bot_api/service/__init__.py +++ b/kdb-bot/src/bot_api/service/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_api.service' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_api/transformer/__init__.py b/kdb-bot/src/bot_api/transformer/__init__.py index 4c614cb9e8..a1915e9f11 100644 --- a/kdb-bot/src/bot_api/transformer/__init__.py +++ b/kdb-bot/src/bot_api/transformer/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_api.transformer' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_core/__init__.py b/kdb-bot/src/bot_core/__init__.py index 75e45f3f6e..9d27fa5529 100644 --- a/kdb-bot/src/bot_core/__init__.py +++ b/kdb-bot/src/bot_core/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_core' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_core/abc/__init__.py b/kdb-bot/src/bot_core/abc/__init__.py index 6bed6e119b..e8949ac9e1 100644 --- a/kdb-bot/src/bot_core/abc/__init__.py +++ b/kdb-bot/src/bot_core/abc/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_core.abc' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_core/configuration/__init__.py b/kdb-bot/src/bot_core/configuration/__init__.py index 0e6f2e1aff..3e2d80ffb1 100644 --- a/kdb-bot/src/bot_core/configuration/__init__.py +++ b/kdb-bot/src/bot_core/configuration/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_core.configuration' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_core/core_extension/__init__.py b/kdb-bot/src/bot_core/core_extension/__init__.py index 201573f413..f6d56342f5 100644 --- a/kdb-bot/src/bot_core/core_extension/__init__.py +++ b/kdb-bot/src/bot_core/core_extension/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_core.core_extension' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_core/events/__init__.py b/kdb-bot/src/bot_core/events/__init__.py index 278da61a17..3ea3777d7a 100644 --- a/kdb-bot/src/bot_core/events/__init__.py +++ b/kdb-bot/src/bot_core/events/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_core.events' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_core/helper/__init__.py b/kdb-bot/src/bot_core/helper/__init__.py index bfd7ff1986..e6122ab2b2 100644 --- a/kdb-bot/src/bot_core/helper/__init__.py +++ b/kdb-bot/src/bot_core/helper/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_core.helper' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_core/logging/__init__.py b/kdb-bot/src/bot_core/logging/__init__.py index 5ae285bb82..7c415dfff7 100644 --- a/kdb-bot/src/bot_core/logging/__init__.py +++ b/kdb-bot/src/bot_core/logging/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_core.logging' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_core/pipes/__init__.py b/kdb-bot/src/bot_core/pipes/__init__.py index e9f62709dc..345eea8d3d 100644 --- a/kdb-bot/src/bot_core/pipes/__init__.py +++ b/kdb-bot/src/bot_core/pipes/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_core.pipes' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_core/service/__init__.py b/kdb-bot/src/bot_core/service/__init__.py index 63cc8d89bc..2e659d24d8 100644 --- a/kdb-bot/src/bot_core/service/__init__.py +++ b/kdb-bot/src/bot_core/service/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_core.service' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_data/__init__.py b/kdb-bot/src/bot_data/__init__.py index 0e69edf43d..6ac4b954df 100644 --- a/kdb-bot/src/bot_data/__init__.py +++ b/kdb-bot/src/bot_data/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_data' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_data/abc/__init__.py b/kdb-bot/src/bot_data/abc/__init__.py index 8a57f0d061..e312030cd9 100644 --- a/kdb-bot/src/bot_data/abc/__init__.py +++ b/kdb-bot/src/bot_data/abc/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_data.abc' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_data/migration/__init__.py b/kdb-bot/src/bot_data/migration/__init__.py index d28a56eefe..b8443711a6 100644 --- a/kdb-bot/src/bot_data/migration/__init__.py +++ b/kdb-bot/src/bot_data/migration/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_data.migration' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_data/model/__init__.py b/kdb-bot/src/bot_data/model/__init__.py index a66634fd59..ba35160cfe 100644 --- a/kdb-bot/src/bot_data/model/__init__.py +++ b/kdb-bot/src/bot_data/model/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_data.model' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/bot_data/service/__init__.py b/kdb-bot/src/bot_data/service/__init__.py index 69c2512501..6ed3776925 100644 --- a/kdb-bot/src/bot_data/service/__init__.py +++ b/kdb-bot/src/bot_data/service/__init__.py @@ -15,7 +15,7 @@ __title__ = 'bot_data.service' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/admin/__init__.py b/kdb-bot/src/modules/admin/__init__.py index bbf3f2b006..fa637ebcab 100644 --- a/kdb-bot/src/modules/admin/__init__.py +++ b/kdb-bot/src/modules/admin/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.admin' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/admin/command/__init__.py b/kdb-bot/src/modules/admin/command/__init__.py index c5035ad0d7..4ca82ff598 100644 --- a/kdb-bot/src/modules/admin/command/__init__.py +++ b/kdb-bot/src/modules/admin/command/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.admin.command' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/auto_role/__init__.py b/kdb-bot/src/modules/auto_role/__init__.py index 6b3e526e57..bb9a5a5fc3 100644 --- a/kdb-bot/src/modules/auto_role/__init__.py +++ b/kdb-bot/src/modules/auto_role/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.auto_role' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/auto_role/command/__init__.py b/kdb-bot/src/modules/auto_role/command/__init__.py index 9e9cc1aef9..580fe9f104 100644 --- a/kdb-bot/src/modules/auto_role/command/__init__.py +++ b/kdb-bot/src/modules/auto_role/command/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.auto_role.command' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/auto_role/events/__init__.py b/kdb-bot/src/modules/auto_role/events/__init__.py index f431645b6a..727f90b8b6 100644 --- a/kdb-bot/src/modules/auto_role/events/__init__.py +++ b/kdb-bot/src/modules/auto_role/events/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.auto_role.events' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/auto_role/helper/__init__.py b/kdb-bot/src/modules/auto_role/helper/__init__.py index d90d3babb7..c0d58dcd01 100644 --- a/kdb-bot/src/modules/auto_role/helper/__init__.py +++ b/kdb-bot/src/modules/auto_role/helper/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.auto_role.helper' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/base/__init__.py b/kdb-bot/src/modules/base/__init__.py index 337ba2d6f4..e3cb6607c5 100644 --- a/kdb-bot/src/modules/base/__init__.py +++ b/kdb-bot/src/modules/base/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.base' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/base/abc/__init__.py b/kdb-bot/src/modules/base/abc/__init__.py index 4396c0e591..a5b10a343d 100644 --- a/kdb-bot/src/modules/base/abc/__init__.py +++ b/kdb-bot/src/modules/base/abc/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.base.abc' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/base/command/__init__.py b/kdb-bot/src/modules/base/command/__init__.py index 7383ff78c9..4ba0eba952 100644 --- a/kdb-bot/src/modules/base/command/__init__.py +++ b/kdb-bot/src/modules/base/command/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.base.command' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/base/configuration/__init__.py b/kdb-bot/src/modules/base/configuration/__init__.py index bf7d4c4720..bd2cc24d26 100644 --- a/kdb-bot/src/modules/base/configuration/__init__.py +++ b/kdb-bot/src/modules/base/configuration/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.base.configuration' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/base/events/__init__.py b/kdb-bot/src/modules/base/events/__init__.py index 3337e0d9e9..04f7a3718a 100644 --- a/kdb-bot/src/modules/base/events/__init__.py +++ b/kdb-bot/src/modules/base/events/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.base.events' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/base/service/__init__.py b/kdb-bot/src/modules/base/service/__init__.py index 37d31ea0b5..92e0c81639 100644 --- a/kdb-bot/src/modules/base/service/__init__.py +++ b/kdb-bot/src/modules/base/service/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.base.service' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/boot_log/__init__.py b/kdb-bot/src/modules/boot_log/__init__.py index a156bb4f92..e5cc21aa32 100644 --- a/kdb-bot/src/modules/boot_log/__init__.py +++ b/kdb-bot/src/modules/boot_log/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.boot_log' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/boot_log/configuration/__init__.py b/kdb-bot/src/modules/boot_log/configuration/__init__.py index 8d1ce4fac4..0d76108eaf 100644 --- a/kdb-bot/src/modules/boot_log/configuration/__init__.py +++ b/kdb-bot/src/modules/boot_log/configuration/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.boot_log.configuration' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/database/__init__.py b/kdb-bot/src/modules/database/__init__.py index 694778b001..0615d2a1d1 100644 --- a/kdb-bot/src/modules/database/__init__.py +++ b/kdb-bot/src/modules/database/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.database' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/moderator/__init__.py b/kdb-bot/src/modules/moderator/__init__.py index 5416853ff6..1b8e00d30b 100644 --- a/kdb-bot/src/modules/moderator/__init__.py +++ b/kdb-bot/src/modules/moderator/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.moderator' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/moderator/command/__init__.py b/kdb-bot/src/modules/moderator/command/__init__.py index beeffcd4a0..e392b8ea45 100644 --- a/kdb-bot/src/modules/moderator/command/__init__.py +++ b/kdb-bot/src/modules/moderator/command/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.moderator.command' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/permission/__init__.py b/kdb-bot/src/modules/permission/__init__.py index 51190b7a2e..f14bcd24c0 100644 --- a/kdb-bot/src/modules/permission/__init__.py +++ b/kdb-bot/src/modules/permission/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.permission' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/permission/abc/__init__.py b/kdb-bot/src/modules/permission/abc/__init__.py index 28a1c61eb3..220dde0db6 100644 --- a/kdb-bot/src/modules/permission/abc/__init__.py +++ b/kdb-bot/src/modules/permission/abc/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.permission.abc' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/permission/configuration/__init__.py b/kdb-bot/src/modules/permission/configuration/__init__.py index 4ad1f1d4c0..1de588132f 100644 --- a/kdb-bot/src/modules/permission/configuration/__init__.py +++ b/kdb-bot/src/modules/permission/configuration/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.permission.configuration' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/permission/events/__init__.py b/kdb-bot/src/modules/permission/events/__init__.py index 6dbd86c1bd..117b3b8b21 100644 --- a/kdb-bot/src/modules/permission/events/__init__.py +++ b/kdb-bot/src/modules/permission/events/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.permission.events' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports: VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') diff --git a/kdb-bot/src/modules/permission/service/__init__.py b/kdb-bot/src/modules/permission/service/__init__.py index 1341ec8db7..8d6d28f103 100644 --- a/kdb-bot/src/modules/permission/service/__init__.py +++ b/kdb-bot/src/modules/permission/service/__init__.py @@ -15,7 +15,7 @@ __title__ = 'modules.permission.service' __author__ = 'Sven Heidemann' __license__ = 'MIT' __copyright__ = 'Copyright (c) 2022 sh-edraft.de' -__version__ = '0.2.3' +__version__ = '0.3.0' from collections import namedtuple @@ -23,4 +23,4 @@ from collections import namedtuple # imports VersionInfo = namedtuple('VersionInfo', 'major minor micro') -version_info = VersionInfo(major='0', minor='2', micro='3') +version_info = VersionInfo(major='0', minor='3', micro='0') From ee49bde9612518370714d6270e841e9610d4a1f0 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 15 Oct 2022 23:48:38 +0200 Subject: [PATCH 021/102] Added waitress dep #70 --- kdb-bot/src/bot/bot.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/kdb-bot/src/bot/bot.json b/kdb-bot/src/bot/bot.json index ff36eea75d..799d3fe8fd 100644 --- a/kdb-bot/src/bot/bot.json +++ b/kdb-bot/src/bot/bot.json @@ -21,11 +21,10 @@ "cpl-query==2022.10.0.post2", "cpl-discord==2022.10.0.post5", "Flask==2.2.2", - "Flask[async]==2.2.2", "Flask-Classful==0.14.2", "Flask-Cors==3.0.10", - "PyJWT[crypto]==2.5.0", - "PyJWT==2.5.0" + "PyJWT==2.5.0", + "waitress==2.1.2" ], "DevDependencies": [ "cpl-cli==2022.10.0" From 8c3cd1fae7fc58550fb169f478fdb4c049d3e6b8 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sun, 16 Oct 2022 00:13:03 +0200 Subject: [PATCH 022/102] Added angular frontend #70 --- kdb-web/.browserslistrc | 16 + kdb-web/.editorconfig | 16 + kdb-web/.gitignore | 43 + kdb-web/README.md | 27 + kdb-web/angular.json | 105 + kdb-web/karma.conf.js | 44 + kdb-web/package-lock.json | 21484 ++++++++++++++++ kdb-web/package.json | 49 + kdb-web/src/app/app-routing.module.ts | 22 + kdb-web/src/app/app.component.html | 36 + kdb-web/src/app/app.component.scss | 0 kdb-web/src/app/app.component.spec.ts | 16 + kdb-web/src/app/app.component.ts | 21 + kdb-web/src/app/app.module.ts | 81 + .../error/not-found/not-found.component.html | 15 + .../error/not-found/not-found.component.scss | 0 .../not-found/not-found.component.spec.ts | 25 + .../error/not-found/not-found.component.ts | 18 + .../components/footer/footer.component.html | 26 + .../components/footer/footer.component.scss | 0 .../footer/footer.component.spec.ts | 25 + .../app/components/footer/footer.component.ts | 46 + .../components/header/header.component.html | 25 + .../components/header/header.component.scss | 0 .../header/header.component.spec.ts | 25 + .../app/components/header/header.component.ts | 168 + .../components/sidebar/sidebar.component.html | 3 + .../components/sidebar/sidebar.component.scss | 0 .../sidebar/sidebar.component.spec.ts | 25 + .../components/sidebar/sidebar.component.ts | 52 + .../components/spinner/spinner.component.html | 7 + .../components/spinner/spinner.component.scss | 0 .../spinner/spinner.component.spec.ts | 25 + .../components/spinner/spinner.component.ts | 18 + .../app/models/auth/admin-update-user.dto.ts | 7 + .../models/auth/auth-error-messages.enum.ts | 7 + .../src/app/models/auth/auth-roles.enum.ts | 4 + .../app/models/auth/auth-user-atr-errors.ts | 12 + kdb-web/src/app/models/auth/auth-user.dto.ts | 11 + .../src/app/models/auth/email-string.dto.ts | 3 + .../auth/register-error-messages.enum.ts | 4 + .../src/app/models/auth/reset-password.dto.ts | 6 + kdb-web/src/app/models/auth/token.dto.ts | 4 + .../src/app/models/auth/update-user.dto.ts | 6 + kdb-web/src/app/models/config/api-version.ts | 5 + kdb-web/src/app/models/config/appsettings.ts | 8 + kdb-web/src/app/models/config/settings.dto.ts | 16 + .../app/models/config/software-version.dto.ts | 5 + .../src/app/models/config/software-version.ts | 19 + kdb-web/src/app/models/error/error-dto.ts | 8 + .../models/error/service-error-code.enum.ts | 16 + .../auth-user-select-criterion.dto.ts | 8 + .../get-filtered-auth-users-result.dto.ts | 6 + .../logins/login-select-criterion.dto.ts | 8 + .../selection/select-criterion.model.ts | 6 + .../app/models/utils/confirmation-dialog.ts | 7 + kdb-web/src/app/models/utils/toast-options.ts | 5 + kdb-web/src/app/models/view/theme.ts | 4 + kdb-web/src/app/models/view/themes.enum.ts | 7 + .../auth-users/auth-user-routing.module.ts | 13 + .../admin/auth-users/auth-user.module.ts | 18 + .../auth-user/auth-user.component.html | 201 + .../auth-user/auth-user.component.scss | 0 .../auth-user/auth-user.component.spec.ts | 25 + .../auth-user/auth-user.component.ts | 330 + .../settings/settings.component.html | 125 + .../settings/settings.component.scss | 0 .../settings/settings.component.spec.ts | 25 + .../components/settings/settings.component.ts | 121 + .../admin/settings/settings-routing.module.ts | 13 + .../modules/admin/settings/settings.module.ts | 19 + .../app/modules/auth/auth-routing.module.ts | 21 + kdb-web/src/app/modules/auth/auth.module.ts | 23 + .../forget-password.component.html | 57 + .../forget-password.component.scss | 0 .../forget-password.component.spec.ts | 25 + .../forget-password.component.ts | 136 + .../components/login/login.component.html | 58 + .../components/login/login.component.scss | 0 .../components/login/login.component.spec.ts | 25 + .../auth/components/login/login.component.ts | 114 + .../registration/registration.component.html | 83 + .../registration/registration.component.scss | 0 .../registration.component.spec.ts | 25 + .../registration/registration.component.ts | 144 + .../shared/guards/auth/auth.guard.spec.ts | 16 + .../modules/shared/guards/auth/auth.guard.ts | 38 + .../modules/shared/pipes/auth-role.pipe.ts | 13 + .../modules/shared/pipes/bool.pipe.spec.ts | 8 + .../src/app/modules/shared/pipes/bool.pipe.ts | 21 + .../modules/shared/pipes/ip-address.pipe.ts | 27 + .../src/app/modules/shared/shared.module.ts | 71 + .../change-password-routing.module.ts | 13 + .../change-password/change-password.module.ts | 19 + .../change-password.component.html | 35 + .../change-password.component.scss | 0 .../change-password.component.spec.ts | 25 + .../change-password.component.ts | 107 + .../dashboard/dashboard.component.html | 3 + .../dashboard/dashboard.component.scss | 0 .../dashboard/dashboard.component.spec.ts | 25 + .../dashboard/dashboard.component.ts | 14 + .../dashboard/dashboard-routing.module.ts | 13 + .../view/dashboard/dashboard.module.ts | 19 + .../user-settings.component.html | 41 + .../user-settings.component.scss | 0 .../user-settings.component.spec.ts | 25 + .../user-settings/user-settings.component.ts | 151 + .../user-settings-routing.module.ts | 13 + .../user-settings/user-settings.module.ts | 19 + .../app/services/auth/auth.service.spec.ts | 16 + kdb-web/src/app/services/auth/auth.service.ts | 243 + .../confirmation-dialog.service.spec.ts | 16 + .../confirmation-dialog.service.ts | 53 + .../app/services/data/data.service.spec.ts | 16 + kdb-web/src/app/services/data/data.service.ts | 14 + .../error-handler.service.spec.ts | 16 + .../error-handler/error-handler.service.ts | 34 + .../src/app/services/gui/gui.service.spec.ts | 16 + kdb-web/src/app/services/gui/gui.service.ts | 41 + .../settings/settings.service.spec.ts | 16 + .../app/services/settings/settings.service.ts | 62 + .../services/spinner/spinner.service.spec.ts | 16 + .../app/services/spinner/spinner.service.ts | 22 + .../app/services/theme/theme.service.spec.ts | 16 + .../src/app/services/theme/theme.service.ts | 98 + .../app/services/toast/toast.service.spec.ts | 16 + .../src/app/services/toast/toast.service.ts | 40 + kdb-web/src/assets/.gitkeep | 0 kdb-web/src/assets/config.json | 26 + kdb-web/src/assets/i18n/de.json | 258 + kdb-web/src/assets/i18n/en.json | 322 + kdb-web/src/assets/images/favicon.ico | Bin 0 -> 948 bytes kdb-web/src/environments/environment.prod.ts | 3 + kdb-web/src/environments/environment.ts | 16 + kdb-web/src/favicon.ico | Bin 0 -> 948 bytes kdb-web/src/index.html | 13 + kdb-web/src/main.ts | 12 + kdb-web/src/polyfills.ts | 53 + kdb-web/src/styles.scss | 394 + kdb-web/src/styles/constants.scss | 2 + kdb-web/src/styles/primeng-fixes.scss | 71 + .../src/styles/themes/default-dark-theme.scss | 517 + .../styles/themes/default-light-theme.scss | 515 + .../styles/themes/sh-edraft-dark-theme.scss | 519 + .../styles/themes/sh-edraft-light-theme.scss | 515 + kdb-web/src/test.ts | 26 + kdb-web/tsconfig.app.json | 15 + kdb-web/tsconfig.json | 32 + kdb-web/tsconfig.spec.json | 18 + kdb-web/update-version.ts | 54 + 151 files changed, 29104 insertions(+) create mode 100644 kdb-web/.browserslistrc create mode 100644 kdb-web/.editorconfig create mode 100644 kdb-web/.gitignore create mode 100644 kdb-web/README.md create mode 100644 kdb-web/angular.json create mode 100644 kdb-web/karma.conf.js create mode 100644 kdb-web/package-lock.json create mode 100644 kdb-web/package.json create mode 100644 kdb-web/src/app/app-routing.module.ts create mode 100644 kdb-web/src/app/app.component.html create mode 100644 kdb-web/src/app/app.component.scss create mode 100644 kdb-web/src/app/app.component.spec.ts create mode 100644 kdb-web/src/app/app.component.ts create mode 100644 kdb-web/src/app/app.module.ts create mode 100644 kdb-web/src/app/components/error/not-found/not-found.component.html create mode 100644 kdb-web/src/app/components/error/not-found/not-found.component.scss create mode 100644 kdb-web/src/app/components/error/not-found/not-found.component.spec.ts create mode 100644 kdb-web/src/app/components/error/not-found/not-found.component.ts create mode 100644 kdb-web/src/app/components/footer/footer.component.html create mode 100644 kdb-web/src/app/components/footer/footer.component.scss create mode 100644 kdb-web/src/app/components/footer/footer.component.spec.ts create mode 100644 kdb-web/src/app/components/footer/footer.component.ts create mode 100644 kdb-web/src/app/components/header/header.component.html create mode 100644 kdb-web/src/app/components/header/header.component.scss create mode 100644 kdb-web/src/app/components/header/header.component.spec.ts create mode 100644 kdb-web/src/app/components/header/header.component.ts create mode 100644 kdb-web/src/app/components/sidebar/sidebar.component.html create mode 100644 kdb-web/src/app/components/sidebar/sidebar.component.scss create mode 100644 kdb-web/src/app/components/sidebar/sidebar.component.spec.ts create mode 100644 kdb-web/src/app/components/sidebar/sidebar.component.ts create mode 100644 kdb-web/src/app/components/spinner/spinner.component.html create mode 100644 kdb-web/src/app/components/spinner/spinner.component.scss create mode 100644 kdb-web/src/app/components/spinner/spinner.component.spec.ts create mode 100644 kdb-web/src/app/components/spinner/spinner.component.ts create mode 100644 kdb-web/src/app/models/auth/admin-update-user.dto.ts create mode 100644 kdb-web/src/app/models/auth/auth-error-messages.enum.ts create mode 100644 kdb-web/src/app/models/auth/auth-roles.enum.ts create mode 100644 kdb-web/src/app/models/auth/auth-user-atr-errors.ts create mode 100644 kdb-web/src/app/models/auth/auth-user.dto.ts create mode 100644 kdb-web/src/app/models/auth/email-string.dto.ts create mode 100644 kdb-web/src/app/models/auth/register-error-messages.enum.ts create mode 100644 kdb-web/src/app/models/auth/reset-password.dto.ts create mode 100644 kdb-web/src/app/models/auth/token.dto.ts create mode 100644 kdb-web/src/app/models/auth/update-user.dto.ts create mode 100644 kdb-web/src/app/models/config/api-version.ts create mode 100644 kdb-web/src/app/models/config/appsettings.ts create mode 100644 kdb-web/src/app/models/config/settings.dto.ts create mode 100644 kdb-web/src/app/models/config/software-version.dto.ts create mode 100644 kdb-web/src/app/models/config/software-version.ts create mode 100644 kdb-web/src/app/models/error/error-dto.ts create mode 100644 kdb-web/src/app/models/error/service-error-code.enum.ts create mode 100644 kdb-web/src/app/models/selection/auth-user/auth-user-select-criterion.dto.ts create mode 100644 kdb-web/src/app/models/selection/auth-user/get-filtered-auth-users-result.dto.ts create mode 100644 kdb-web/src/app/models/selection/logins/login-select-criterion.dto.ts create mode 100644 kdb-web/src/app/models/selection/select-criterion.model.ts create mode 100644 kdb-web/src/app/models/utils/confirmation-dialog.ts create mode 100644 kdb-web/src/app/models/utils/toast-options.ts create mode 100644 kdb-web/src/app/models/view/theme.ts create mode 100644 kdb-web/src/app/models/view/themes.enum.ts create mode 100644 kdb-web/src/app/modules/admin/auth-users/auth-user-routing.module.ts create mode 100644 kdb-web/src/app/modules/admin/auth-users/auth-user.module.ts create mode 100644 kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.html create mode 100644 kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.scss create mode 100644 kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.spec.ts create mode 100644 kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts create mode 100644 kdb-web/src/app/modules/admin/settings/components/settings/settings.component.html create mode 100644 kdb-web/src/app/modules/admin/settings/components/settings/settings.component.scss create mode 100644 kdb-web/src/app/modules/admin/settings/components/settings/settings.component.spec.ts create mode 100644 kdb-web/src/app/modules/admin/settings/components/settings/settings.component.ts create mode 100644 kdb-web/src/app/modules/admin/settings/settings-routing.module.ts create mode 100644 kdb-web/src/app/modules/admin/settings/settings.module.ts create mode 100644 kdb-web/src/app/modules/auth/auth-routing.module.ts create mode 100644 kdb-web/src/app/modules/auth/auth.module.ts create mode 100644 kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.html create mode 100644 kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.scss create mode 100644 kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.spec.ts create mode 100644 kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.ts create mode 100644 kdb-web/src/app/modules/auth/components/login/login.component.html create mode 100644 kdb-web/src/app/modules/auth/components/login/login.component.scss create mode 100644 kdb-web/src/app/modules/auth/components/login/login.component.spec.ts create mode 100644 kdb-web/src/app/modules/auth/components/login/login.component.ts create mode 100644 kdb-web/src/app/modules/auth/components/registration/registration.component.html create mode 100644 kdb-web/src/app/modules/auth/components/registration/registration.component.scss create mode 100644 kdb-web/src/app/modules/auth/components/registration/registration.component.spec.ts create mode 100644 kdb-web/src/app/modules/auth/components/registration/registration.component.ts create mode 100644 kdb-web/src/app/modules/shared/guards/auth/auth.guard.spec.ts create mode 100644 kdb-web/src/app/modules/shared/guards/auth/auth.guard.ts create mode 100644 kdb-web/src/app/modules/shared/pipes/auth-role.pipe.ts create mode 100644 kdb-web/src/app/modules/shared/pipes/bool.pipe.spec.ts create mode 100644 kdb-web/src/app/modules/shared/pipes/bool.pipe.ts create mode 100644 kdb-web/src/app/modules/shared/pipes/ip-address.pipe.ts create mode 100644 kdb-web/src/app/modules/shared/shared.module.ts create mode 100644 kdb-web/src/app/modules/view/change-password/change-password-routing.module.ts create mode 100644 kdb-web/src/app/modules/view/change-password/change-password.module.ts create mode 100644 kdb-web/src/app/modules/view/change-password/components/change-password/change-password.component.html create mode 100644 kdb-web/src/app/modules/view/change-password/components/change-password/change-password.component.scss create mode 100644 kdb-web/src/app/modules/view/change-password/components/change-password/change-password.component.spec.ts create mode 100644 kdb-web/src/app/modules/view/change-password/components/change-password/change-password.component.ts create mode 100644 kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.html create mode 100644 kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.scss create mode 100644 kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.spec.ts create mode 100644 kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts create mode 100644 kdb-web/src/app/modules/view/dashboard/dashboard-routing.module.ts create mode 100644 kdb-web/src/app/modules/view/dashboard/dashboard.module.ts create mode 100644 kdb-web/src/app/modules/view/user-settings/components/user-settings/user-settings.component.html create mode 100644 kdb-web/src/app/modules/view/user-settings/components/user-settings/user-settings.component.scss create mode 100644 kdb-web/src/app/modules/view/user-settings/components/user-settings/user-settings.component.spec.ts create mode 100644 kdb-web/src/app/modules/view/user-settings/components/user-settings/user-settings.component.ts create mode 100644 kdb-web/src/app/modules/view/user-settings/user-settings-routing.module.ts create mode 100644 kdb-web/src/app/modules/view/user-settings/user-settings.module.ts create mode 100644 kdb-web/src/app/services/auth/auth.service.spec.ts create mode 100644 kdb-web/src/app/services/auth/auth.service.ts create mode 100644 kdb-web/src/app/services/confirmation-dialog/confirmation-dialog.service.spec.ts create mode 100644 kdb-web/src/app/services/confirmation-dialog/confirmation-dialog.service.ts create mode 100644 kdb-web/src/app/services/data/data.service.spec.ts create mode 100644 kdb-web/src/app/services/data/data.service.ts create mode 100644 kdb-web/src/app/services/error-handler/error-handler.service.spec.ts create mode 100644 kdb-web/src/app/services/error-handler/error-handler.service.ts create mode 100644 kdb-web/src/app/services/gui/gui.service.spec.ts create mode 100644 kdb-web/src/app/services/gui/gui.service.ts create mode 100644 kdb-web/src/app/services/settings/settings.service.spec.ts create mode 100644 kdb-web/src/app/services/settings/settings.service.ts create mode 100644 kdb-web/src/app/services/spinner/spinner.service.spec.ts create mode 100644 kdb-web/src/app/services/spinner/spinner.service.ts create mode 100644 kdb-web/src/app/services/theme/theme.service.spec.ts create mode 100644 kdb-web/src/app/services/theme/theme.service.ts create mode 100644 kdb-web/src/app/services/toast/toast.service.spec.ts create mode 100644 kdb-web/src/app/services/toast/toast.service.ts create mode 100644 kdb-web/src/assets/.gitkeep create mode 100644 kdb-web/src/assets/config.json create mode 100644 kdb-web/src/assets/i18n/de.json create mode 100644 kdb-web/src/assets/i18n/en.json create mode 100644 kdb-web/src/assets/images/favicon.ico create mode 100644 kdb-web/src/environments/environment.prod.ts create mode 100644 kdb-web/src/environments/environment.ts create mode 100644 kdb-web/src/favicon.ico create mode 100644 kdb-web/src/index.html create mode 100644 kdb-web/src/main.ts create mode 100644 kdb-web/src/polyfills.ts create mode 100644 kdb-web/src/styles.scss create mode 100644 kdb-web/src/styles/constants.scss create mode 100644 kdb-web/src/styles/primeng-fixes.scss create mode 100644 kdb-web/src/styles/themes/default-dark-theme.scss create mode 100644 kdb-web/src/styles/themes/default-light-theme.scss create mode 100644 kdb-web/src/styles/themes/sh-edraft-dark-theme.scss create mode 100644 kdb-web/src/styles/themes/sh-edraft-light-theme.scss create mode 100644 kdb-web/src/test.ts create mode 100644 kdb-web/tsconfig.app.json create mode 100644 kdb-web/tsconfig.json create mode 100644 kdb-web/tsconfig.spec.json create mode 100644 kdb-web/update-version.ts diff --git a/kdb-web/.browserslistrc b/kdb-web/.browserslistrc new file mode 100644 index 0000000000..4f9ac26980 --- /dev/null +++ b/kdb-web/.browserslistrc @@ -0,0 +1,16 @@ +# This file is used by the build system to adjust CSS and JS output to support the specified browsers below. +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries + +# For the full list of supported browsers by the Angular framework, please see: +# https://angular.io/guide/browser-support + +# You can see what browsers were selected by your queries by running: +# npx browserslist + +last 1 Chrome version +last 1 Firefox version +last 2 Edge major versions +last 2 Safari major versions +last 2 iOS major versions +Firefox ESR diff --git a/kdb-web/.editorconfig b/kdb-web/.editorconfig new file mode 100644 index 0000000000..59d9a3a3e7 --- /dev/null +++ b/kdb-web/.editorconfig @@ -0,0 +1,16 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.ts] +quote_type = single + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/kdb-web/.gitignore b/kdb-web/.gitignore new file mode 100644 index 0000000000..c03363f80d --- /dev/null +++ b/kdb-web/.gitignore @@ -0,0 +1,43 @@ +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# Compiled output +/dist +/tmp +/out-tsc +/bazel-out + +# Node +/node_modules +npm-debug.log +yarn-error.log + +# IDEs and editors +.idea/ +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# Visual Studio Code +.vscode/* +.vscode +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# Miscellaneous +/.angular/cache +.sass-cache/ +/connect.lock +/coverage +/libpeerconnection.log +testem.log +/typings + +# System files +.DS_Store +Thumbs.db diff --git a/kdb-web/README.md b/kdb-web/README.md new file mode 100644 index 0000000000..74406fd507 --- /dev/null +++ b/kdb-web/README.md @@ -0,0 +1,27 @@ +# KdbWeb + +This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.0.0. + +## Development server + +Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. + +## Code scaffolding + +Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. + +## Build + +Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. + +## Running unit tests + +Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). + +## Running end-to-end tests + +Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. + +## Further help + +To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. diff --git a/kdb-web/angular.json b/kdb-web/angular.json new file mode 100644 index 0000000000..ee3ffca437 --- /dev/null +++ b/kdb-web/angular.json @@ -0,0 +1,105 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "kdb-web": { + "projectType": "application", + "schematics": { + "@schematics/angular:component": { + "style": "scss" + }, + "@schematics/angular:application": { + "strict": true + } + }, + "root": "", + "sourceRoot": "src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "outputPath": "dist/kdb-web", + "index": "src/index.html", + "main": "src/main.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "tsconfig.app.json", + "inlineStyleLanguage": "scss", + "assets": ["src/favicon.ico", "src/assets"], + "styles": [ + "src/styles.scss", + "node_modules/primeicons/primeicons.css", + "node_modules/primeng/resources/themes/lara-light-blue/theme.css", + "node_modules/primeng/resources/primeng.min.css" + ], + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "outputHashing": "all" + }, + "development": { + "buildOptimizer": false, + "optimization": false, + "vendorChunk": true, + "extractLicenses": false, + "sourceMap": true, + "namedChunks": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "browserTarget": "kdb-web:build:production" + }, + "development": { + "browserTarget": "kdb-web:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "kdb-web:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "src/test.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "tsconfig.spec.json", + "karmaConfig": "karma.conf.js", + "inlineStyleLanguage": "scss", + "assets": ["src/favicon.ico", "src/assets"], + "styles": ["src/styles.scss"], + "scripts": [] + } + } + } + } + } +} diff --git a/kdb-web/karma.conf.js b/kdb-web/karma.conf.js new file mode 100644 index 0000000000..187127578c --- /dev/null +++ b/kdb-web/karma.conf.js @@ -0,0 +1,44 @@ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + jasmine: { + // you can add configuration options for Jasmine here + // the possible options are listed at https://jasmine.github.io/api/edge/Configuration.html + // for example, you can disable the random execution with `random: false` + // or set a specific seed with `seed: 4321` + }, + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + jasmineHtmlReporter: { + suppressAll: true // removes the duplicated traces + }, + coverageReporter: { + dir: require('path').join(__dirname, './coverage/kdb-web'), + subdir: '.', + reporters: [ + { type: 'html' }, + { type: 'text-summary' } + ] + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false, + restartOnFileChange: true + }); +}; diff --git a/kdb-web/package-lock.json b/kdb-web/package-lock.json new file mode 100644 index 0000000000..46d080cf42 --- /dev/null +++ b/kdb-web/package-lock.json @@ -0,0 +1,21484 @@ +{ + "name": "kdb-web", + "version": "0.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "kdb-web", + "version": "0.0.0", + "dependencies": { + "@angular/animations": "^14.0.0", + "@angular/common": "^14.0.0", + "@angular/compiler": "^14.0.0", + "@angular/core": "^14.0.0", + "@angular/forms": "^14.0.0", + "@angular/platform-browser": "^14.0.0", + "@angular/platform-browser-dynamic": "^14.0.0", + "@angular/router": "^14.0.0", + "@auth0/angular-jwt": "^5.1.0", + "@microsoft/signalr": "^6.0.9", + "@ngx-translate/core": "^14.0.0", + "@ngx-translate/http-loader": "^7.0.0", + "primeicons": "^6.0.1", + "primeng": "^14.1.2", + "rxjs": "~7.5.0", + "tslib": "^2.3.0", + "zone.js": "~0.11.4" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^14.0.0", + "@angular/cli": "~14.0.0", + "@angular/compiler-cli": "^14.0.0", + "@types/jasmine": "~4.0.0", + "@types/node": "^18.8.3", + "jasmine-core": "~4.1.0", + "karma": "~6.3.0", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage": "~2.2.0", + "karma-jasmine": "~5.0.0", + "karma-jasmine-html-reporter": "~1.7.0", + "ts-node": "~8.3.0", + "typescript": "~4.7.2" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.0.1.tgz", + "integrity": "sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g==", + "dev": true + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@angular-devkit/architect": { + "version": "0.1402.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1402.5.tgz", + "integrity": "sha512-vtJEwB51UEY1Q7FCI7xGLdhdb2SRTtI1Qs0or95momn85NuxlaMQsXK1Wxu9/EwtWKZK8dXePXbB/hpiNt61JQ==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "14.2.5", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/architect/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/architect/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@angular-devkit/build-angular": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.2.5.tgz", + "integrity": "sha512-jSgH11E+zs1C24lXj7R/PgXsTUpoYoMr1GtO6mpVROgXL5czVlL+b/B1p2HwbcAKuI9WXb48X6OZ6fOZhDQlSg==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "2.2.0", + "@angular-devkit/architect": "0.1402.5", + "@angular-devkit/build-webpack": "0.1402.5", + "@angular-devkit/core": "14.2.5", + "@babel/core": "7.18.10", + "@babel/generator": "7.18.12", + "@babel/helper-annotate-as-pure": "7.18.6", + "@babel/plugin-proposal-async-generator-functions": "7.18.10", + "@babel/plugin-transform-async-to-generator": "7.18.6", + "@babel/plugin-transform-runtime": "7.18.10", + "@babel/preset-env": "7.18.10", + "@babel/runtime": "7.18.9", + "@babel/template": "7.18.10", + "@discoveryjs/json-ext": "0.5.7", + "@ngtools/webpack": "14.2.5", + "ansi-colors": "4.1.3", + "babel-loader": "8.2.5", + "babel-plugin-istanbul": "6.1.1", + "browserslist": "^4.9.1", + "cacache": "16.1.2", + "copy-webpack-plugin": "11.0.0", + "critters": "0.0.16", + "css-loader": "6.7.1", + "esbuild-wasm": "0.15.5", + "glob": "8.0.3", + "https-proxy-agent": "5.0.1", + "inquirer": "8.2.4", + "jsonc-parser": "3.1.0", + "karma-source-map-support": "1.4.0", + "less": "4.1.3", + "less-loader": "11.0.0", + "license-webpack-plugin": "4.0.2", + "loader-utils": "3.2.0", + "mini-css-extract-plugin": "2.6.1", + "minimatch": "5.1.0", + "open": "8.4.0", + "ora": "5.4.1", + "parse5-html-rewriting-stream": "6.0.1", + "piscina": "3.2.0", + "postcss": "8.4.16", + "postcss-import": "15.0.0", + "postcss-loader": "7.0.1", + "postcss-preset-env": "7.8.0", + "regenerator-runtime": "0.13.9", + "resolve-url-loader": "5.0.0", + "rxjs": "6.6.7", + "sass": "1.54.4", + "sass-loader": "13.0.2", + "semver": "7.3.7", + "source-map-loader": "4.0.0", + "source-map-support": "0.5.21", + "stylus": "0.59.0", + "stylus-loader": "7.0.0", + "terser": "5.14.2", + "text-table": "0.2.0", + "tree-kill": "1.2.2", + "tslib": "2.4.0", + "webpack": "5.74.0", + "webpack-dev-middleware": "5.3.3", + "webpack-dev-server": "4.11.0", + "webpack-merge": "5.8.0", + "webpack-subresource-integrity": "5.1.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "optionalDependencies": { + "esbuild": "0.15.5" + }, + "peerDependencies": { + "@angular/compiler-cli": "^14.0.0", + "@angular/localize": "^14.0.0", + "@angular/service-worker": "^14.0.0", + "karma": "^6.3.0", + "ng-packagr": "^14.0.0", + "protractor": "^7.0.0", + "tailwindcss": "^2.0.0 || ^3.0.0", + "typescript": ">=4.6.2 <4.9" + }, + "peerDependenciesMeta": { + "@angular/localize": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "karma": { + "optional": true + }, + "ng-packagr": { + "optional": true + }, + "protractor": { + "optional": true + }, + "tailwindcss": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/rxjs/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.1402.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.5.tgz", + "integrity": "sha512-h+o0GZD9iATwWjaTiUR0lJ3QZ9twUOJ1sotRchXHzAXMuaDk8wqqPriL5S0qDMlA2QqpNt4OD9rodUCRwae7fw==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1402.5", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^5.30.0", + "webpack-dev-server": "^4.0.0" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/build-webpack/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@angular-devkit/core": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.5.tgz", + "integrity": "sha512-lSje+HX0fx9Y2A4k63jVHrWdGT4wellhwcZpTCv9P6LvdfTkAlrfra3TaYhUPjavCsPwlRC/VVQN3Qkzk5m6gA==", + "dev": true, + "dependencies": { + "ajv": "8.11.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.1.0", + "rxjs": "6.6.7", + "source-map": "0.7.4" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/core/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/core/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@angular-devkit/schematics": { + "version": "14.0.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-14.0.7.tgz", + "integrity": "sha512-nJUJXCBQr7rmVn6IXFAXMCWAB1w6JQmFGuFVW0G3GH/A0e+A3ttzJc6qVLYluqaFoafw394cZu24YJo55E/+Zg==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "14.0.7", + "jsonc-parser": "3.0.0", + "magic-string": "0.26.1", + "ora": "5.4.1", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/@angular-devkit/core": { + "version": "14.0.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.0.7.tgz", + "integrity": "sha512-XBqK2OMVKkV1Ltkh4aBsoHoDJQlins5a6qa/ZMjW4reYx90qLERs8ZfeWlRUWhvn2/ohx4aPq77jwSR5avp/Cw==", + "dev": true, + "dependencies": { + "ajv": "8.11.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.0.0", + "rxjs": "6.6.7", + "source-map": "0.7.3" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/schematics/node_modules/jsonc-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "dev": true + }, + "node_modules/@angular-devkit/schematics/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@angular-devkit/schematics/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@angular/animations": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-14.2.5.tgz", + "integrity": "sha512-4BhR9jSjgIwoK/alu7FSwSU5SxISMVFBAl/4cEYchfCqnflMNkZ8WwRVKTQjyeuYW5KtQTw9jRNp4tGK1YQWYw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/core": "14.2.5" + } + }, + "node_modules/@angular/cli": { + "version": "14.0.7", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-14.0.7.tgz", + "integrity": "sha512-tABt1EDwBHm0ngsutdkXXWgPgHzapGLC7rSPHXStMc24ngViFZpXGzBCpompjHvXNt6bjklmJmuRvjS6+ktBZA==", + "dev": true, + "dependencies": { + "@angular-devkit/architect": "0.1400.7", + "@angular-devkit/core": "14.0.7", + "@angular-devkit/schematics": "14.0.7", + "@schematics/angular": "14.0.7", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.1", + "debug": "4.3.4", + "ini": "3.0.0", + "inquirer": "8.2.4", + "jsonc-parser": "3.0.0", + "npm-package-arg": "9.0.2", + "npm-pick-manifest": "7.0.1", + "open": "8.4.0", + "ora": "5.4.1", + "pacote": "13.3.0", + "resolve": "1.22.0", + "semver": "7.3.7", + "symbol-observable": "4.0.0", + "uuid": "8.3.2", + "yargs": "17.4.1" + }, + "bin": { + "ng": "bin/ng.js" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/cli/node_modules/@angular-devkit/architect": { + "version": "0.1400.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1400.7.tgz", + "integrity": "sha512-8dv/Ql86dHajsHYjjr5jvpiV7uXWbt7Mz4K/rGiOi+zzDNKPcZcuCejulWhOySDcCPjT/an47Qcwr+awL4Wr4g==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "14.0.7", + "rxjs": "6.6.7" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/cli/node_modules/@angular-devkit/core": { + "version": "14.0.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.0.7.tgz", + "integrity": "sha512-XBqK2OMVKkV1Ltkh4aBsoHoDJQlins5a6qa/ZMjW4reYx90qLERs8ZfeWlRUWhvn2/ohx4aPq77jwSR5avp/Cw==", + "dev": true, + "dependencies": { + "ajv": "8.11.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.0.0", + "rxjs": "6.6.7", + "source-map": "0.7.3" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular/cli/node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@angular/cli/node_modules/jsonc-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "dev": true + }, + "node_modules/@angular/cli/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@angular/cli/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@angular/cli/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@angular/common": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.2.5.tgz", + "integrity": "sha512-v2fIK6imfMkUvYNjZQO+drE39QO3eSS95Yy7UN+6inb47DkAfzx6hipA9zKrMENjsS3kDv1d7cgDHE7WuOCzIw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/core": "14.2.5", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/compiler": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-14.2.5.tgz", + "integrity": "sha512-L7d2/D6o9wlB2ugqRYpev6a8JntqS+7lF2o6z8y7RR2YAlAu71nq0BDsQez4/aSCK3HnDq0yhEnns7vcmOq/jA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/core": "14.2.5" + }, + "peerDependenciesMeta": { + "@angular/core": { + "optional": true + } + } + }, + "node_modules/@angular/compiler-cli": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-14.2.5.tgz", + "integrity": "sha512-3GYzTPw96TfJjw7Aso+f+uN6VFBWedqRATUQ6v+BAEyZIboirdLI1JQFOcCfuKWUM2B48RW+pdIduZmG3ckotA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.17.2", + "chokidar": "^3.0.0", + "convert-source-map": "^1.5.1", + "dependency-graph": "^0.11.0", + "magic-string": "^0.26.0", + "reflect-metadata": "^0.1.2", + "semver": "^7.0.0", + "sourcemap-codec": "^1.4.8", + "tslib": "^2.3.0", + "yargs": "^17.2.1" + }, + "bin": { + "ng-xi18n": "bundles/src/bin/ng_xi18n.js", + "ngc": "bundles/src/bin/ngc.js", + "ngcc": "bundles/ngcc/main-ngcc.js" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/compiler": "14.2.5", + "typescript": ">=4.6.2 <4.9" + } + }, + "node_modules/@angular/core": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.2.5.tgz", + "integrity": "sha512-Ok78Abq0puMGlolvNVzKFvsX7ePDkyxpZzztDzXDdRA4x4o6bAuuDG9Y7Wab2+wsdY6NktO+dFQjq1UBWClgSg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.11.4" + } + }, + "node_modules/@angular/forms": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-14.2.5.tgz", + "integrity": "sha512-aMH5Vrftny0KF0XzWQIGfHoI0LVQ2aatpWzdUWiUqBeX/Q+ucmxeP5rZyKtUsi0flETWxdRZSBTjbXZ3dsIcTA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/common": "14.2.5", + "@angular/core": "14.2.5", + "@angular/platform-browser": "14.2.5", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/platform-browser": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-14.2.5.tgz", + "integrity": "sha512-FDZm23N9veSEouQX1YuZUjv7Nillroi+v0VbN1x5iPpFZEudaoZYT3A7bpJwdlxUx/4rGS0caaXNhN3CowtIeQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/animations": "14.2.5", + "@angular/common": "14.2.5", + "@angular/core": "14.2.5" + }, + "peerDependenciesMeta": { + "@angular/animations": { + "optional": true + } + } + }, + "node_modules/@angular/platform-browser-dynamic": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-14.2.5.tgz", + "integrity": "sha512-7W8oLs8YEGRr8izgUlpHgBfg3vUb5H0yicTHJY4zIqHJJbG1rTl46CjULaMjYM/FWcS8o7y6XJJcHx0c7pKNsw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/common": "14.2.5", + "@angular/compiler": "14.2.5", + "@angular/core": "14.2.5", + "@angular/platform-browser": "14.2.5" + } + }, + "node_modules/@angular/router": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-14.2.5.tgz", + "integrity": "sha512-AUHcr9Lln7emJ/aete08UoqWQFZOLH1MhuP78r2pixvnNiZ9C8hcevX1rGGax0Po/Gy4PSJ4wnFhZPgifqCguQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0" + }, + "peerDependencies": { + "@angular/common": "14.2.5", + "@angular/core": "14.2.5", + "@angular/platform-browser": "14.2.5", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@assemblyscript/loader": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", + "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", + "dev": true + }, + "node_modules/@auth0/angular-jwt": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@auth0/angular-jwt/-/angular-jwt-5.1.0.tgz", + "integrity": "sha512-EAQoNKPQSZYphcX6FnY2e7xQpD4ZdHQ1DbHq/m+G1U1qA60m3XnhdjPPfu+blVHARlxEbRzWXc48UOVrnMsrZw==", + "dependencies": { + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/common": ">=12.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.4.tgz", + "integrity": "sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.10.tgz", + "integrity": "sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.10", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.10", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.10", + "@babel/types": "^7.18.10", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.18.12", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz", + "integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.10", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "dev": true, + "dependencies": { + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz", + "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.19.3", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz", + "integrity": "sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", + "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0-0" + } + }, + "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", + "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.18.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", + "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", + "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.19.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", + "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", + "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.4.tgz", + "integrity": "sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.4", + "@babel/types": "^7.19.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.4.tgz", + "integrity": "sha512-qpVT7gtuOLjWeDTKLkJ6sryqLliBaFpAtGeqw5cs5giLldvh+Ch0plqnUMKoVAUS6ZEueQQiZV+p5pxtPitEsA==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.10.tgz", + "integrity": "sha512-1mFuY2TOsR1hxbjCo4QL+qlIjV07p4H4EUYw2J/WCqsvFV6V9X9z9YhXbWndc/4fw+hYGlDT7egYxliMp5O6Ew==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-static-block": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", + "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-json-strings": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.19.4.tgz", + "integrity": "sha512-wHmj6LDxVDnL+3WhXteUBaoM1aVILZODAUjg11kHqG4cOlfgMQGxw6aCgvrXrmaJR3Bn14oZhImyCPZzRpC93Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.18.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", + "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz", + "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", + "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.19.4.tgz", + "integrity": "sha512-934S2VLLlt2hRJwPf4MczaOr4hYF0z+VKPwqTNxyKX7NthTiPfhuKFWQZHXRM0vh/wo/VyXB3s4bZUNA08l+tQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz", + "integrity": "sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.19.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.19.4.tgz", + "integrity": "sha512-t0j0Hgidqf0aM86dF8U+vXYReUgJnlv4bZLsyoPnwZNrGY+7/38o8YjaELrvHeVfTZao15kjR0PVv0nju2iduA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz", + "integrity": "sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz", + "integrity": "sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.0.tgz", + "integrity": "sha512-x9aiR0WXAWmOWsqcsnrzGR+ieaTMVyGyffPVA7F8cXAGt/UxefYv6uSHZLkAFChN5M5Iy1+wjE+xJuPt22H39A==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-identifier": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", + "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz", + "integrity": "sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", + "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.10.tgz", + "integrity": "sha512-q5mMeYAdfEbpBAgzl7tBre/la3LeCxmDO1+wMXRdPWbcoMjR3GiXlCLk7JBZVVye0bqTGNMbt0yYVXX1B1jEWQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", + "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.18.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.10.tgz", + "integrity": "sha512-wVxs1yjFdW3Z/XkNfXKoblxoHgbtUF7/l3PvvP4m02Qz9TZ6uZGxRVYjSQeR87oQmHco9zWitW5J82DJ7sCjvA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.18.10", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.18.9", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@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-import-assertions": "^7.18.6", + "@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.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.18.9", + "@babel/plugin-transform-classes": "^7.18.9", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.18.9", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.18.9", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.18.6", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.18.9", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.18.10", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", + "core-js-compat": "^3.22.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "dev": true, + "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" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", + "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.4.tgz", + "integrity": "sha512-w3K1i+V5u2aJUOXBFFC5pveFLmtq1s3qcdDNC2qRI6WPBQIDaKFqXxDEqDO/h1dQ3HjsZoZMyIy6jGLq0xtw+g==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.4", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.19.4", + "@babel/types": "^7.19.4", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/generator": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.4.tgz", + "integrity": "sha512-5T2lY5vXqS+5UEit/5TwcIUeCnwgCljcF8IQRT6XRQPBrvLeq5V8W+URv+GvwoF3FP8tkhp++evVyDzkDGzNmA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.19.4", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@csstools/postcss-cascade-layers": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", + "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.2", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-color-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", + "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-font-format-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", + "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-hwb-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", + "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-ic-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", + "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-is-pseudo-class": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", + "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-nested-calc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-1.0.0.tgz", + "integrity": "sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-normalize-display-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", + "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-oklab-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", + "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-progressive-custom-properties": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", + "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/@csstools/postcss-stepped-value-functions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", + "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-text-decoration-shorthand": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-1.0.0.tgz", + "integrity": "sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-trigonometric-functions": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", + "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/postcss-unset-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", + "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/@csstools/selector-specificity": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz", + "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2", + "postcss-selector-parser": "^6.0.10" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.5.tgz", + "integrity": "sha512-UHkDFCfSGTuXq08oQltXxSZmH1TXyWsL+4QhZDWvvLl6mEJQqk3u7/wq1LjhrrAXYIllaTtRSzUXl4Olkf2J8A==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.16", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.16.tgz", + "integrity": "sha512-LCQ+NeThyJ4k1W2d+vIKdxuSt9R3pQSZ4P92m7EakaYuXcVWbHuT5bjNcqLd4Rdgi6xYWYDvBJZJLZSLanjDcA==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "dev": true + }, + "node_modules/@microsoft/signalr": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-6.0.9.tgz", + "integrity": "sha512-DGVYe3ycT2PfRU7m3xCbv1HjhvClKl2VB1HyFlvf8SqBGXz3Cx+oalNWGYrGIgADA6Q2xaB4GaDmDdprTa2U0Q==", + "dependencies": { + "abort-controller": "^3.0.0", + "eventsource": "^1.0.7", + "fetch-cookie": "^0.11.0", + "node-fetch": "^2.6.7", + "ws": "^7.4.5" + } + }, + "node_modules/@microsoft/signalr/node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@ngtools/webpack": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.5.tgz", + "integrity": "sha512-Thwq1WyOOq1PIWMcjAAqKI1hbvGC0ywxbNoDadOlWpEFm6k0dvXC6Zm9lnVkePjxlPfagvbnv55+Lv9Vmygc1g==", + "dev": true, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^14.0.0", + "typescript": ">=4.6.2 <4.9", + "webpack": "^5.54.0" + } + }, + "node_modules/@ngx-translate/core": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-14.0.0.tgz", + "integrity": "sha512-UevdwNCXMRCdJv//0kC8h2eSfmi02r29xeE8E9gJ1Al4D4jEJ7eiLPdjslTMc21oJNGguqqWeEVjf64SFtvw2w==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/core": ">=13.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@ngx-translate/http-loader": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-7.0.0.tgz", + "integrity": "sha512-j+NpXXlcGVdyUNyY/qsJrqqeAdJdizCd+GKh3usXExSqy1aE9866jlAIL+xrfDU4w+LiMoma5pgE4emvFebZmA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": ">=13.0.0", + "@ngx-translate/core": ">=14.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "dev": true, + "dependencies": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-3.0.2.tgz", + "integrity": "sha512-CAcd08y3DWBJqJDpfuVL0uijlq5oaXaOJEKHKc4wqrjd00gkvTZB+nFuLn+doOOKddaQS9JfqtNoFCO2LCvA3w==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^3.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^7.0.0", + "proc-log": "^2.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", + "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "dev": true, + "dependencies": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + }, + "bin": { + "installed-package-contents": "index.js" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@npmcli/move-file": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz", + "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-3.0.0.tgz", + "integrity": "sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g==", + "dev": true, + "dependencies": { + "infer-owner": "^1.0.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-3.0.3.tgz", + "integrity": "sha512-ZXL6qgC5NjwfZJ2nET+ZSLEz/PJgJ/5CU90C2S66dZY4Jw73DasS4ZCXuy/KHWYP0imjJ4VtA+Gebb5BxxKp9Q==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "node-gyp": "^8.4.1", + "read-package-json-fast": "^2.0.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/@schematics/angular": { + "version": "14.0.7", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-14.0.7.tgz", + "integrity": "sha512-I0v1gNFpm9ReL/hUzwjjOa+hk0qvlXv/vjITAWnlUV5dba6FZxzwsrTGsGO6t5XMNsm6QtwpDYDRdy9uy/n/1g==", + "dev": true, + "dependencies": { + "@angular-devkit/core": "14.0.7", + "@angular-devkit/schematics": "14.0.7", + "jsonc-parser": "3.0.0" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@schematics/angular/node_modules/@angular-devkit/core": { + "version": "14.0.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.0.7.tgz", + "integrity": "sha512-XBqK2OMVKkV1Ltkh4aBsoHoDJQlins5a6qa/ZMjW4reYx90qLERs8ZfeWlRUWhvn2/ohx4aPq77jwSR5avp/Cw==", + "dev": true, + "dependencies": { + "ajv": "8.11.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.0.0", + "rxjs": "6.6.7", + "source-map": "0.7.3" + }, + "engines": { + "node": "^14.15.0 || >=16.10.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@schematics/angular/node_modules/jsonc-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "dev": true + }, + "node_modules/@schematics/angular/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@schematics/angular/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@schematics/angular/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", + "dev": true + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", + "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "dev": true, + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, + "node_modules/@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", + "dev": true + }, + "node_modules/@types/eslint": { + "version": "8.4.6", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.6.tgz", + "integrity": "sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", + "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.31", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", + "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/http-proxy": { + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", + "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/jasmine": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-4.0.3.tgz", + "integrity": "sha512-Opp1LvvEuZdk8fSSvchK2mZwhVrsNT0JgJE9Di6MjnaIpmEXM8TLCPPrVtNTYh8+5MPdY8j9bAHMu2SSfwpZJg==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.8.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz", + "integrity": "sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==", + "dev": true + }, + "node_modules/@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "node_modules/@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dev": true, + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "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" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "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" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "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" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "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" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "dependencies": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/agentkeepalive/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "node_modules/autoprefixer": { + "version": "10.4.12", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.12.tgz", + "integrity": "sha512-WrCGV9/b97Pa+jtwf5UGaRjgQIg7OK3D06GnoYoZNcG1Xb8Gt3EfuKjlhh9i/VtT16g6PYjZ69jdJ2g8FxSC4Q==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-lite": "^1.0.30001407", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/babel-loader": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "dev": true, + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-loader/node_modules/loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz", + "integrity": "sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.2", + "core-js-compat": "^3.21.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true, + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/bonjour-service": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.14.tgz", + "integrity": "sha512-HIMbgLnk1Vqvs6B4Wq5ep7mxvj9sGz5d1JJyDNSGNIdA/w2MCz6GTjWTdjqOJV1bEPj+6IkxDvWNFKEBxNt4kQ==", + "dev": true, + "dependencies": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "16.1.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.2.tgz", + "integrity": "sha512-Xx+xPlfCZIUHagysjjOAje9nRo8pRDczQCcXb4J2O0BLtH+xeVue6ba4y1kfJfQMAnM2mkcoMIAyOctlaRGWYA==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001418", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz", + "integrity": "sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "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" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/core-js-compat": { + "version": "3.25.5", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.25.5.tgz", + "integrity": "sha512-ovcyhs2DEBUIE0MGEKHP4olCUW/XYte3Vroyxuh38rD1wAO4dHohsovUC4eAOuzFxE6b+RXvBU3UZ9o0YhUTkA==", + "dev": true, + "dependencies": { + "browserslist": "^4.21.4" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "dev": true, + "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" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/critters": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", + "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "css-select": "^4.2.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "postcss": "^8.3.7", + "pretty-bytes": "^5.3.0" + } + }, + "node_modules/critters/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/critters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/critters/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/critters/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/critters/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/critters/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-blank-pseudo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", + "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-blank-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-has-pseudo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", + "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "bin": { + "css-has-pseudo": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-loader": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", + "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/css-prefers-color-scheme": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "dev": true, + "bin": { + "css-prefers-color-scheme": "dist/cli.cjs" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssdb": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.0.1.tgz", + "integrity": "sha512-pT3nzyGM78poCKLAEy2zWIVX2hikq6dIrjuZzLV98MumBg+xMTNYfHx7paUlfiRTgg91O/vR889CIf+qiv79Rw==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", + "dev": true + }, + "node_modules/date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "node_modules/di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", + "dev": true + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", + "dev": true + }, + "node_modules/dns-packet": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", + "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", + "dev": true, + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", + "dev": true, + "dependencies": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.276", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.276.tgz", + "integrity": "sha512-EpuHPqu8YhonqLBXHoU6hDJCD98FCe6KDoet3/gY1qsQ6usjJoHqBH2YIVs8FXaAtHwVL8Uqa/fsYao/vq9VWQ==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/engine.io": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz", + "integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==", + "dev": true, + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.2.3" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", + "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", + "dev": true + }, + "node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.5.tgz", + "integrity": "sha512-VSf6S1QVqvxfIsSKb3UKr3VhUCis7wgDbtF4Vd9z84UJr05/Sp2fRKmzC+CSPG/dNAPPJZ0BTBLTT1Fhd6N9Gg==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/linux-loong64": "0.15.5", + "esbuild-android-64": "0.15.5", + "esbuild-android-arm64": "0.15.5", + "esbuild-darwin-64": "0.15.5", + "esbuild-darwin-arm64": "0.15.5", + "esbuild-freebsd-64": "0.15.5", + "esbuild-freebsd-arm64": "0.15.5", + "esbuild-linux-32": "0.15.5", + "esbuild-linux-64": "0.15.5", + "esbuild-linux-arm": "0.15.5", + "esbuild-linux-arm64": "0.15.5", + "esbuild-linux-mips64le": "0.15.5", + "esbuild-linux-ppc64le": "0.15.5", + "esbuild-linux-riscv64": "0.15.5", + "esbuild-linux-s390x": "0.15.5", + "esbuild-netbsd-64": "0.15.5", + "esbuild-openbsd-64": "0.15.5", + "esbuild-sunos-64": "0.15.5", + "esbuild-windows-32": "0.15.5", + "esbuild-windows-64": "0.15.5", + "esbuild-windows-arm64": "0.15.5" + } + }, + "node_modules/esbuild-android-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.5.tgz", + "integrity": "sha512-dYPPkiGNskvZqmIK29OPxolyY3tp+c47+Fsc2WYSOVjEPWNCHNyqhtFqQadcXMJDQt8eN0NMDukbyQgFcHquXg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-android-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.5.tgz", + "integrity": "sha512-YyEkaQl08ze3cBzI/4Cm1S+rVh8HMOpCdq8B78JLbNFHhzi4NixVN93xDrHZLztlocEYqi45rHHCgA8kZFidFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.5.tgz", + "integrity": "sha512-Cr0iIqnWKx3ZTvDUAzG0H/u9dWjLE4c2gTtRLz4pqOBGjfjqdcZSfAObFzKTInLLSmD0ZV1I/mshhPoYSBMMCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-darwin-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.5.tgz", + "integrity": "sha512-WIfQkocGtFrz7vCu44ypY5YmiFXpsxvz2xqwe688jFfSVCnUsCn2qkEVDo7gT8EpsLOz1J/OmqjExePL1dr1Kg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.5.tgz", + "integrity": "sha512-M5/EfzV2RsMd/wqwR18CELcenZ8+fFxQAAEO7TJKDmP3knhWSbD72ILzrXFMMwshlPAS1ShCZ90jsxkm+8FlaA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-freebsd-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.5.tgz", + "integrity": "sha512-2JQQ5Qs9J0440F/n/aUBNvY6lTo4XP/4lt1TwDfHuo0DY3w5++anw+jTjfouLzbJmFFiwmX7SmUhMnysocx96w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-32": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.5.tgz", + "integrity": "sha512-gO9vNnIN0FTUGjvTFucIXtBSr1Woymmx/aHQtuU+2OllGU6YFLs99960UD4Dib1kFovVgs59MTXwpFdVoSMZoQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.5.tgz", + "integrity": "sha512-ne0GFdNLsm4veXbTnYAWjbx3shpNKZJUd6XpNbKNUZaNllDZfYQt0/zRqOg0sc7O8GQ+PjSMv9IpIEULXVTVmg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.5.tgz", + "integrity": "sha512-wvAoHEN+gJ/22gnvhZnS/+2H14HyAxM07m59RSLn3iXrQsdS518jnEWRBnJz3fR6BJa+VUTo0NxYjGaNt7RA7Q==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.5.tgz", + "integrity": "sha512-7EgFyP2zjO065XTfdCxiXVEk+f83RQ1JsryN1X/VSX2li9rnHAt2swRbpoz5Vlrl6qjHrCmq5b6yxD13z6RheA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-mips64le": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.5.tgz", + "integrity": "sha512-KdnSkHxWrJ6Y40ABu+ipTZeRhFtc8dowGyFsZY5prsmMSr1ZTG9zQawguN4/tunJ0wy3+kD54GaGwdcpwWAvZQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-ppc64le": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.5.tgz", + "integrity": "sha512-QdRHGeZ2ykl5P0KRmfGBZIHmqcwIsUKWmmpZTOq573jRWwmpfRmS7xOhmDHBj9pxv+6qRMH8tLr2fe+ZKQvCYw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-riscv64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.5.tgz", + "integrity": "sha512-p+WE6RX+jNILsf+exR29DwgV6B73khEQV0qWUbzxaycxawZ8NE0wA6HnnTxbiw5f4Gx9sJDUBemh9v49lKOORA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-linux-s390x": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.5.tgz", + "integrity": "sha512-J2ngOB4cNzmqLHh6TYMM/ips8aoZIuzxJnDdWutBw5482jGXiOzsPoEF4j2WJ2mGnm7FBCO4StGcwzOgic70JQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-netbsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.5.tgz", + "integrity": "sha512-MmKUYGDizYjFia0Rwt8oOgmiFH7zaYlsoQ3tIOfPxOqLssAsEgG0MUdRDm5lliqjiuoog8LyDu9srQk5YwWF3w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-openbsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.5.tgz", + "integrity": "sha512-2mMFfkLk3oPWfopA9Plj4hyhqHNuGyp5KQyTT9Rc8hFd8wAn5ZrbJg+gNcLMo2yzf8Uiu0RT6G9B15YN9WQyMA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-sunos-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.5.tgz", + "integrity": "sha512-2sIzhMUfLNoD+rdmV6AacilCHSxZIoGAU2oT7XmJ0lXcZWnCvCtObvO6D4puxX9YRE97GodciRGDLBaiC6x1SA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-wasm": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.15.5.tgz", + "integrity": "sha512-lTJOEKekN/4JI/eOEq0wLcx53co2N6vaT/XjBz46D1tvIVoUEyM0o2K6txW6gEotf31szFD/J1PbxmnbkGlK9A==", + "dev": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-32": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.5.tgz", + "integrity": "sha512-e+duNED9UBop7Vnlap6XKedA/53lIi12xv2ebeNS4gFmu7aKyTrok7DPIZyU5w/ftHD4MUDs5PJUkQPP9xJRzg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.5.tgz", + "integrity": "sha512-v+PjvNtSASHOjPDMIai9Yi+aP+Vwox+3WVdg2JB8N9aivJ7lyhp4NVU+J0MV2OkWFPnVO8AE/7xH+72ibUUEnw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild-windows-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.5.tgz", + "integrity": "sha512-Yz8w/D8CUPYstvVQujByu6mlf48lKmXkq6bkeSZZxTA626efQOJb26aDGLzmFWx6eg/FwrXgt6SZs9V8Pwy/aA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter-asyncresource": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", + "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", + "dev": true + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/eventsource": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.2.tgz", + "integrity": "sha512-xAH3zWhgO2/3KIniEKYPr8plNSzlGINOUqYj0m0u7AB81iRw8b/3E73W6AuU+6klLbaSFmZnaETQ2lXPfAydrA==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "node_modules/express/node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/express/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "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" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fetch-cookie": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.11.0.tgz", + "integrity": "sha512-BQm7iZLFhMWFy5CZ/162sAGjBfdNWb7a8LEqqnzsHFhxT/X/SVj/z2t2nu3aJvjlbQkrAlTUApplPRjWyH4mhA==", + "dependencies": { + "tough-cookie": "^2.3.3 || ^3.0.1 || ^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", + "dev": true + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", + "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==", + "dev": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "node_modules/hdr-histogram-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", + "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", + "dev": true, + "dependencies": { + "@assemblyscript/loader": "^0.10.1", + "base64-js": "^1.2.0", + "pako": "^1.0.3" + } + }, + "node_modules/hdr-histogram-percentiles-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", + "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", + "dev": true + }, + "node_modules/hosted-git-info": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.1.0.tgz", + "integrity": "sha512-Ek+QmMEqZF8XrbFdwoDjSbm7rT23pCgEMOJmz6GPk/s4yH//RQfNPArhIxbguNxROq/+5lNBwCDHMhA903Kx1Q==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "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" + } + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", + "dev": true + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "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" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-5.0.1.tgz", + "integrity": "sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==", + "dev": true, + "dependencies": { + "minimatch": "^5.0.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/immutable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", + "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", + "dev": true + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.0.tgz", + "integrity": "sha512-TxYQaeNW/N8ymDvwAxPyRbhMBtnEwuvaTYpOQkFx1nSeusgezHniEc/l35Vo4iCq/mMiTJbpD7oYxN98hFlfmw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/inquirer/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/inquirer/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/inquirer/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/inquirer/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + }, + "node_modules/ipaddr.js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", + "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jasmine-core": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.1.1.tgz", + "integrity": "sha512-lmUfT5XcK9KKvt3lLYzn93hc4MGzlUBowExFVgzbSW0ZCrdeyS574dfsyfRhxbg81Wj4gk+RxUiTnj7KBfDA1g==", + "dev": true + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.1.0.tgz", + "integrity": "sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/karma": { + "version": "6.3.20", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.3.20.tgz", + "integrity": "sha512-HRNQhMuKOwKpjYlWiJP0DUrJOh+QjaI/DTaD8b9rEm4Il3tJ8MijutVZH4ts10LuUFst/CedwTS6vieCN8yTSw==", + "dev": true, + "dependencies": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.4.1", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "bin": { + "karma": "bin/karma" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/karma-chrome-launcher": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz", + "integrity": "sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ==", + "dev": true, + "dependencies": { + "which": "^1.2.1" + } + }, + "node_modules/karma-coverage": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.0.tgz", + "integrity": "sha512-gPVdoZBNDZ08UCzdMHHhEImKrw1+PAOQOIiffv1YsvxFhBjqvo/SVXNk4tqn1SYqX0BJZT6S/59zgxiBe+9OuA==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.1", + "istanbul-reports": "^3.0.5", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/karma-coverage/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/karma-coverage/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/karma-jasmine": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.0.1.tgz", + "integrity": "sha512-FkL1Kk+JAKmim8VWU8RXKZBpl0lLI7J8LijM0/q7oP7emfB6QMZV1Az+JgqGKSLpF0tYaav+KUVFQroZUxQTHA==", + "dev": true, + "dependencies": { + "jasmine-core": "^4.1.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "karma": "^6.0.0" + } + }, + "node_modules/karma-jasmine-html-reporter": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.7.0.tgz", + "integrity": "sha512-pzum1TL7j90DTE86eFt48/s12hqwQuiD+e5aXx2Dc9wDEn2LfGq6RoAxEZZjFiN0RDSCOnosEKRZWxbQ+iMpQQ==", + "dev": true, + "peerDependencies": { + "jasmine-core": ">=3.8", + "karma": ">=0.9", + "karma-jasmine": ">=1.1" + } + }, + "node_modules/karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "dependencies": { + "source-map-support": "^0.5.5" + } + }, + "node_modules/karma/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/karma/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/karma/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/karma/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/karma/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/karma/node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/karma/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "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" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/karma/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klona": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", + "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/less": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", + "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", + "dev": true, + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less-loader": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.0.0.tgz", + "integrity": "sha512-9+LOWWjuoectIEx3zrfN83NAGxSUB5pWEabbbidVQVgZhN+wN68pOvuyirVlH1IK4VT1f3TmlyvAnCXh8O5KEw==", + "dev": true, + "dependencies": { + "klona": "^2.0.4" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "less": "^3.5.0 || ^4.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/less/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/less/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/less/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/license-webpack-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "dev": true, + "dependencies": { + "webpack-sources": "^3.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-sources": { + "optional": true + } + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true, + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz", + "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log4js": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.7.0.tgz", + "integrity": "sha512-KA0W9ffgNBLDj6fZCq/lRbgR6ABAodRIDHrZnS48vOtfKa4PzWImb0Md1lmGCdO3n3sbCm/n1/WmrNlZ8kCI3Q==", + "dev": true, + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.3" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/lru-cache": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.0.tgz", + "integrity": "sha512-EIRtP1GrSJny0dqb50QXRUNBxHJhcpxHC++M5tD7RYbvLLn5KVWKsbyswSSqDuU15UFi3bgTQIY8nhDMeF6aDQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/magic-string": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.1.tgz", + "integrity": "sha512-ndThHmvgtieXe8J/VGPjG+Apu7v7ItcD5mhEIvOscWjPF/ccOiLxHaSuCAS2G+3x4GKsAbT8u7zdyamupui8Tg==", + "dev": true, + "dependencies": { + "sourcemap-codec": "^1.4.8" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/make-fetch-happen/node_modules/@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "dev": true, + "dependencies": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "node_modules/make-fetch-happen/node_modules/@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-fetch-happen/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/make-fetch-happen/node_modules/cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/make-fetch-happen/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/make-fetch-happen/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-fetch-happen/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/make-fetch-happen/node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.7.tgz", + "integrity": "sha512-ygaiUSNalBX85388uskeCyhSAoOSgzBbtVCr9jA2RROssFL9Q19/ZXFqS+2Th2sr1ewNIWgFdLzLC3Yl1Zv+lw==", + "dev": true, + "dependencies": { + "fs-monkey": "^1.0.3" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", + "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", + "dev": true, + "dependencies": { + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "node_modules/minipass": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz", + "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "dev": true, + "dependencies": { + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/needle": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.1.0.tgz", + "integrity": "sha512-gCE9weDhjVGCRqS8dwDR/D3GTAeyXLXuqp7I8EzH6DllZGXSUyxuqqLh+YX9rMAWaaTFyVAg6rHGL25dqvczKw==", + "dev": true, + "optional": true, + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "optional": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/needle/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "!win32" + ], + "dependencies": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "optional": true + }, + "node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true, + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-gyp": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/node-gyp-build": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", + "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==", + "dev": true, + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-gyp/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "dev": true + }, + "node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/normalize-package-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-4.0.1.tgz", + "integrity": "sha512-EBk5QKKuocMJhB3BILuKhmaPjI8vNRSpIfO9woLC6NyHVkKKdVEdAO1mrT0ZfxNR1lKwCcTkuZfmGIFdizZ8Pg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^5.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-bundled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "node_modules/npm-install-checks": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-5.0.0.tgz", + "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "node_modules/npm-package-arg": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.0.2.tgz", + "integrity": "sha512-v/miORuX8cndiOheW8p2moNuPJ7QhcFh9WGlTorruG8hXSA23vMTEp5hTCmDxic0nD8KHhj/NQgFuySD3GYY3g==", + "dev": true, + "dependencies": { + "hosted-git-info": "^5.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-packlist": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-5.1.3.tgz", + "integrity": "sha512-263/0NGrn32YFYi4J533qzrQ/krmmrWwhKkzwTuM4f/07ug51odoaNjUexxO4vxlzURHcmYMH1QjvHjsNDKLVg==", + "dev": true, + "dependencies": { + "glob": "^8.0.1", + "ignore-walk": "^5.0.1", + "npm-bundled": "^2.0.0", + "npm-normalize-package-bin": "^2.0.0" + }, + "bin": { + "npm-packlist": "bin/index.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-packlist/node_modules/npm-bundled": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-2.0.1.tgz", + "integrity": "sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-packlist/node_modules/npm-normalize-package-bin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-7.0.1.tgz", + "integrity": "sha512-IA8+tuv8KujbsbLQvselW2XQgmXWS47t3CB0ZrzsRZ82DbDfkcFunOaPm4X7qNuhMfq+FmV7hQT4iFVpHqV7mg==", + "dev": true, + "dependencies": { + "npm-install-checks": "^5.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-13.3.1.tgz", + "integrity": "sha512-eukJPi++DKRTjSBRcDZSDDsGqRK3ehbxfFUcgaRd0Yp6kRwOwh2WVn0r+8rMB4nnuzvAk6rQVzl6K5CkYOmnvw==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-registry-fetch/node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm-registry-fetch/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/npm-registry-fetch/node_modules/make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/npm-registry-fetch/node_modules/minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "dependencies": { + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/npm-registry-fetch/node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dev": true, + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ora/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/ora/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pacote": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-13.3.0.tgz", + "integrity": "sha512-auhJAUlfC2TALo6I0s1vFoPvVFgWGx+uz/PnIojTTgkGwlK3Np8sGJ0ghfFhiuzJXTZoTycMLk8uLskdntPbDw==", + "dev": true, + "dependencies": { + "@npmcli/git": "^3.0.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/promise-spawn": "^3.0.0", + "@npmcli/run-script": "^3.0.1", + "cacache": "^16.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.6", + "mkdirp": "^1.0.4", + "npm-package-arg": "^9.0.0", + "npm-packlist": "^5.0.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.1", + "proc-log": "^2.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "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" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "node_modules/parse5-html-rewriting-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-6.0.1.tgz", + "integrity": "sha512-vwLQzynJVEfUlURxgnf51yAJDQTtVpNyGD8tKi2Za7m+akukNHxCcUQMAa/mUGLhCeicFdpy7Tlvj8ZNKadprg==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1", + "parse5-sax-parser": "^6.0.1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parse5-sax-parser": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-6.0.1.tgz", + "integrity": "sha512-kXX+5S81lgESA0LsDuGjAlBybImAChYRMT+/uKCEXFBFOeEhS52qUCydGhU3qLRD8D9DVjaUo821WK7DM4iCeg==", + "dev": true, + "dependencies": { + "parse5": "^6.0.1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/piscina": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", + "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", + "dev": true, + "dependencies": { + "eventemitter-asyncresource": "^1.0.0", + "hdr-histogram-js": "^2.0.1", + "hdr-histogram-percentiles-obj": "^3.0.0" + }, + "optionalDependencies": { + "nice-napi": "^1.0.2" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss": { + "version": "8.4.16", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", + "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-attribute-case-insensitive": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", + "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-clamp": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", + "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": ">=7.6.0" + }, + "peerDependencies": { + "postcss": "^8.4.6" + } + }, + "node_modules/postcss-color-functional-notation": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", + "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-color-hex-alpha": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", + "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-color-rebeccapurple": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", + "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-custom-media": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", + "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-custom-properties": { + "version": "12.1.9", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.9.tgz", + "integrity": "sha512-/E7PRvK8DAVljBbeWrcEQJPG72jaImxF3vvCNFwv9cC8CzigVoNIpeyfnJzphnN3Fd8/auBf5wvkw6W9MfmTyg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-custom-selectors": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", + "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.3" + } + }, + "node_modules/postcss-dir-pseudo-class": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", + "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-double-position-gradients": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", + "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-env-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", + "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-visible": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", + "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-focus-within": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", + "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.9" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "dev": true, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-gap-properties": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", + "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-image-set-function": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", + "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-import": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.0.0.tgz", + "integrity": "sha512-Y20shPQ07RitgBGv2zvkEAu9bqvrD77C9axhj/aA1BQj4czape2MdClCExvB27EwYEJdGgKZBpKanb0t1rK2Kg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-initial": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "dev": true, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-lab-function": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", + "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "dev": true, + "dependencies": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-loader": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.1.tgz", + "integrity": "sha512-VRviFEyYlLjctSM93gAZtcJJ/iSkPZ79zWbN/1fSH+NisBByEiVLqpdVDrPLVSi8DX0oJo12kL/GppTBdKVXiQ==", + "dev": true, + "dependencies": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.7" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + } + }, + "node_modules/postcss-logical": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", + "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "dev": true, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "peerDependencies": { + "postcss": "^8.4" + } + }, + "node_modules/postcss-media-minmax": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", + "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-nesting": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", + "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", + "dev": true, + "dependencies": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-opacity-percentage": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.2.tgz", + "integrity": "sha512-lyUfF7miG+yewZ8EAk9XUBIlrHyUE6fijnesuz+Mj5zrIHIEw6KcIZSOk/elVMqzLvREmXB83Zi/5QpNRYd47w==", + "dev": true, + "funding": [ + { + "type": "kofi", + "url": "https://ko-fi.com/mrcgrtz" + }, + { + "type": "liberapay", + "url": "https://liberapay.com/mrcgrtz" + } + ], + "engines": { + "node": "^12 || ^14 || >=16" + } + }, + "node_modules/postcss-overflow-shorthand": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", + "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "dev": true, + "peerDependencies": { + "postcss": "^8" + } + }, + "node_modules/postcss-place": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", + "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-preset-env": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.0.tgz", + "integrity": "sha512-leqiqLOellpLKfbHkD06E04P6d9ZQ24mat6hu4NSqun7WG0UhspHR5Myiv/510qouCjoo4+YJtNOqg5xHaFnCA==", + "dev": true, + "dependencies": { + "@csstools/postcss-cascade-layers": "^1.0.5", + "@csstools/postcss-color-function": "^1.1.1", + "@csstools/postcss-font-format-keywords": "^1.0.1", + "@csstools/postcss-hwb-function": "^1.0.2", + "@csstools/postcss-ic-unit": "^1.0.1", + "@csstools/postcss-is-pseudo-class": "^2.0.7", + "@csstools/postcss-nested-calc": "^1.0.0", + "@csstools/postcss-normalize-display-values": "^1.0.1", + "@csstools/postcss-oklab-function": "^1.1.1", + "@csstools/postcss-progressive-custom-properties": "^1.3.0", + "@csstools/postcss-stepped-value-functions": "^1.0.1", + "@csstools/postcss-text-decoration-shorthand": "^1.0.0", + "@csstools/postcss-trigonometric-functions": "^1.0.2", + "@csstools/postcss-unset-value": "^1.0.2", + "autoprefixer": "^10.4.8", + "browserslist": "^4.21.3", + "css-blank-pseudo": "^3.0.3", + "css-has-pseudo": "^3.0.4", + "css-prefers-color-scheme": "^6.0.3", + "cssdb": "^7.0.0", + "postcss-attribute-case-insensitive": "^5.0.2", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^4.2.4", + "postcss-color-hex-alpha": "^8.0.4", + "postcss-color-rebeccapurple": "^7.1.1", + "postcss-custom-media": "^8.0.2", + "postcss-custom-properties": "^12.1.8", + "postcss-custom-selectors": "^6.0.3", + "postcss-dir-pseudo-class": "^6.0.5", + "postcss-double-position-gradients": "^3.1.2", + "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.5", + "postcss-image-set-function": "^4.0.7", + "postcss-initial": "^4.0.1", + "postcss-lab-function": "^4.2.1", + "postcss-logical": "^5.0.4", + "postcss-media-minmax": "^5.0.0", + "postcss-nesting": "^10.1.10", + "postcss-opacity-percentage": "^1.1.2", + "postcss-overflow-shorthand": "^3.0.4", + "postcss-page-break": "^3.0.4", + "postcss-place": "^7.0.5", + "postcss-pseudo-class-any-link": "^7.1.6", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^6.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-pseudo-class-any-link": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", + "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "dev": true, + "peerDependencies": { + "postcss": "^8.0.3" + } + }, + "node_modules/postcss-selector-not": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", + "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^12 || ^14 || >=16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + }, + "peerDependencies": { + "postcss": "^8.2" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/primeicons": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/primeicons/-/primeicons-6.0.1.tgz", + "integrity": "sha512-KDeO94CbWI4pKsPnYpA1FPjo79EsY9I+M8ywoPBSf9XMXoe/0crjbUK7jcQEDHuc0ZMRIZsxH3TYLv4TUtHmAA==" + }, + "node_modules/primeng": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/primeng/-/primeng-14.1.2.tgz", + "integrity": "sha512-iLMeORiLD46SNAotxCwRXoaRMXLs3ZbFzyePrPSNAFQbKEbsLfpUvsAUAatb/TA0jd8TnXgdCjZ07ee4664XVQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^14.0.0", + "@angular/core": "^14.0.0", + "@angular/forms": "^14.0.0", + "primeicons": "^6.0.1", + "rxjs": "^6.0.0 || ^7.0.0", + "zone.js": "^0.10.2 || ^0.11.0" + } + }, + "node_modules/proc-log": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "optional": true + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true, + "engines": { + "node": ">=0.9" + } + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/read-package-json": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-5.0.2.tgz", + "integrity": "sha512-BSzugrt4kQ/Z0krro8zhTwV1Kd79ue25IhNN/VtHFy1mG/6Tluyi+msc0UpwaoQzxSHa28mntAjIZY6kEgfR9Q==", + "dev": true, + "dependencies": { + "glob": "^8.0.1", + "json-parse-even-better-errors": "^2.3.1", + "normalize-package-data": "^4.0.0", + "npm-normalize-package-bin": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", + "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/read-package-json/node_modules/npm-normalize-package-bin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", + "dev": true + }, + "node_modules/regexpu-core": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz", + "integrity": "sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsgen": "^0.7.1", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", + "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==", + "dev": true + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "dev": true, + "dependencies": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/resolve-url-loader/node_modules/loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", + "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "devOptional": true + }, + "node_modules/sass": { + "version": "1.54.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.4.tgz", + "integrity": "sha512-3tmF16yvnBwtlPrNBHw/H907j8MlOX8aTBnlNX1yrKx24RKcJGPyLhFUwkoKBKesR3unP93/2z14Ll8NicwQUA==", + "dev": true, + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/sass-loader": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.0.2.tgz", + "integrity": "sha512-BbiqbVmbfJaWVeOOAu2o7DhYWtcNmTfvroVgFXa6k2hHheMxNAeDHLNoDy/Q5aoaVlz0LH+MbMktKwm9vN/j8Q==", + "dev": true, + "dependencies": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + } + } + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "dev": true, + "dependencies": { + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "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" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socket.io": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.2.tgz", + "integrity": "sha512-6fCnk4ARMPZN448+SQcnn1u8OHUC72puJcNtSgg2xS34Cu7br1gQ09YKkO1PFfDn/wyUE9ZgMAwosJed003+NQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.2", + "engine.io": "~6.2.0", + "socket.io-adapter": "~2.4.0", + "socket.io-parser": "~4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz", + "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==", + "dev": true + }, + "node_modules/socket.io-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", + "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", + "dev": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dev": true, + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", + "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.0.tgz", + "integrity": "sha512-i3KVgM3+QPAHNbGavK+VBq03YoJl24m9JWNbLgsjTj8aJzXG9M61bantBTNBt7CNwY2FYf+RJRYJ3pzalKjIrw==", + "dev": true, + "dependencies": { + "abab": "^2.0.6", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.72.1" + } + }, + "node_modules/source-map-loader/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", + "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", + "dev": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "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" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "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" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/streamroller": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.3.tgz", + "integrity": "sha512-CphIJyFx2SALGHeINanjFRKQ4l7x2c+rXYJ4BMq0gd+ZK0gi4VT8b+eHe2wi58x4UayBAKx4xtHpXT/ea1cz8w==", + "dev": true, + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/stylus": { + "version": "0.59.0", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.59.0.tgz", + "integrity": "sha512-lQ9w/XIOH5ZHVNuNbWW8D822r+/wBSO/d6XvtyHLF7LW4KaCIDeVbvn5DF8fGCJAUCwVhVi/h6J0NUcnylUEjg==", + "dev": true, + "dependencies": { + "@adobe/css-tools": "^4.0.1", + "debug": "^4.3.2", + "glob": "^7.1.6", + "sax": "~1.2.4", + "source-map": "^0.7.3" + }, + "bin": { + "stylus": "bin/stylus" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://opencollective.com/stylus" + } + }, + "node_modules/stylus-loader": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-7.0.0.tgz", + "integrity": "sha512-WTbtLrNfOfLgzTaR9Lj/BPhQroKk/LC1hfTXSUbrxmxgfUo3Y3LpmKRVA2R1XbjvTAvOfaian9vOyfv1z99E+A==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "klona": "^2.0.5", + "normalize-path": "^3.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "stylus": ">=0.52.4", + "webpack": "^5.0.0" + } + }, + "node_modules/stylus/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/stylus/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/stylus/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/terser": { + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", + "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.14", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.14.1" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", + "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-node": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.3.0.tgz", + "integrity": "sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ==", + "dev": true, + "dependencies": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.6", + "yn": "^3.0.0" + }, + "bin": { + "ts-node": "dist/bin.js" + }, + "engines": { + "node": ">=4.2.0" + }, + "peerDependencies": { + "typescript": ">=2.0" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "dev": true + }, + "node_modules/typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", + "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", + "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/webpack": { + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", + "dev": true, + "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.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "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-even-better-errors": "^2.3.1", + "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.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.0.tgz", + "integrity": "sha512-L5S4Q2zT57SK7tazgzjMiSMBdsw+rGYIX27MgPgx7LDhWO0lViPrHKoLS7jo5In06PWYAhlYu3PbyoC6yAThbw==", + "dev": true, + "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/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.0.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.9.0.tgz", + "integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "dev": true, + "dependencies": { + "typed-assert": "^1.0.8" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", + "webpack": "^5.12.0" + }, + "peerDependenciesMeta": { + "html-webpack-plugin": { + "optional": true + } + } + }, + "node_modules/webpack/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "17.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.4.1.tgz", + "integrity": "sha512-WSZD9jgobAg3ZKuCQZSa3g9QOJeCCqLoLAykiWgmXnDo9EPnn4RPf5qVTtzgOx66o6/oqhcA5tHtJXpG8pMt3g==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/zone.js": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.8.tgz", + "integrity": "sha512-82bctBg2hKcEJ21humWIkXRlLBBmrc3nN7DFh5LGGhcyycO2S7FN8NmdvlcKaGFDNVL4/9kFLmwmInTavdJERA==", + "dependencies": { + "tslib": "^2.3.0" + } + } + }, + "dependencies": { + "@adobe/css-tools": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.0.1.tgz", + "integrity": "sha512-+u76oB43nOHrF4DDWRLWDCtci7f3QJoEBigemIdIeTi1ODqjx6Tad9NCVnPRwewWlKkVab5PlK8DCtPTyX7S8g==", + "dev": true + }, + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@angular-devkit/architect": { + "version": "0.1402.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1402.5.tgz", + "integrity": "sha512-vtJEwB51UEY1Q7FCI7xGLdhdb2SRTtI1Qs0or95momn85NuxlaMQsXK1Wxu9/EwtWKZK8dXePXbB/hpiNt61JQ==", + "dev": true, + "requires": { + "@angular-devkit/core": "14.2.5", + "rxjs": "6.6.7" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular-devkit/build-angular": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.2.5.tgz", + "integrity": "sha512-jSgH11E+zs1C24lXj7R/PgXsTUpoYoMr1GtO6mpVROgXL5czVlL+b/B1p2HwbcAKuI9WXb48X6OZ6fOZhDQlSg==", + "dev": true, + "requires": { + "@ampproject/remapping": "2.2.0", + "@angular-devkit/architect": "0.1402.5", + "@angular-devkit/build-webpack": "0.1402.5", + "@angular-devkit/core": "14.2.5", + "@babel/core": "7.18.10", + "@babel/generator": "7.18.12", + "@babel/helper-annotate-as-pure": "7.18.6", + "@babel/plugin-proposal-async-generator-functions": "7.18.10", + "@babel/plugin-transform-async-to-generator": "7.18.6", + "@babel/plugin-transform-runtime": "7.18.10", + "@babel/preset-env": "7.18.10", + "@babel/runtime": "7.18.9", + "@babel/template": "7.18.10", + "@discoveryjs/json-ext": "0.5.7", + "@ngtools/webpack": "14.2.5", + "ansi-colors": "4.1.3", + "babel-loader": "8.2.5", + "babel-plugin-istanbul": "6.1.1", + "browserslist": "^4.9.1", + "cacache": "16.1.2", + "copy-webpack-plugin": "11.0.0", + "critters": "0.0.16", + "css-loader": "6.7.1", + "esbuild": "0.15.5", + "esbuild-wasm": "0.15.5", + "glob": "8.0.3", + "https-proxy-agent": "5.0.1", + "inquirer": "8.2.4", + "jsonc-parser": "3.1.0", + "karma-source-map-support": "1.4.0", + "less": "4.1.3", + "less-loader": "11.0.0", + "license-webpack-plugin": "4.0.2", + "loader-utils": "3.2.0", + "mini-css-extract-plugin": "2.6.1", + "minimatch": "5.1.0", + "open": "8.4.0", + "ora": "5.4.1", + "parse5-html-rewriting-stream": "6.0.1", + "piscina": "3.2.0", + "postcss": "8.4.16", + "postcss-import": "15.0.0", + "postcss-loader": "7.0.1", + "postcss-preset-env": "7.8.0", + "regenerator-runtime": "0.13.9", + "resolve-url-loader": "5.0.0", + "rxjs": "6.6.7", + "sass": "1.54.4", + "sass-loader": "13.0.2", + "semver": "7.3.7", + "source-map-loader": "4.0.0", + "source-map-support": "0.5.21", + "stylus": "0.59.0", + "stylus-loader": "7.0.0", + "terser": "5.14.2", + "text-table": "0.2.0", + "tree-kill": "1.2.2", + "tslib": "2.4.0", + "webpack": "5.74.0", + "webpack-dev-middleware": "5.3.3", + "webpack-dev-server": "4.11.0", + "webpack-merge": "5.8.0", + "webpack-subresource-integrity": "5.1.0" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + } + } + }, + "@angular-devkit/build-webpack": { + "version": "0.1402.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.5.tgz", + "integrity": "sha512-h+o0GZD9iATwWjaTiUR0lJ3QZ9twUOJ1sotRchXHzAXMuaDk8wqqPriL5S0qDMlA2QqpNt4OD9rodUCRwae7fw==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.1402.5", + "rxjs": "6.6.7" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular-devkit/core": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.5.tgz", + "integrity": "sha512-lSje+HX0fx9Y2A4k63jVHrWdGT4wellhwcZpTCv9P6LvdfTkAlrfra3TaYhUPjavCsPwlRC/VVQN3Qkzk5m6gA==", + "dev": true, + "requires": { + "ajv": "8.11.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.1.0", + "rxjs": "6.6.7", + "source-map": "0.7.4" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular-devkit/schematics": { + "version": "14.0.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-14.0.7.tgz", + "integrity": "sha512-nJUJXCBQr7rmVn6IXFAXMCWAB1w6JQmFGuFVW0G3GH/A0e+A3ttzJc6qVLYluqaFoafw394cZu24YJo55E/+Zg==", + "dev": true, + "requires": { + "@angular-devkit/core": "14.0.7", + "jsonc-parser": "3.0.0", + "magic-string": "0.26.1", + "ora": "5.4.1", + "rxjs": "6.6.7" + }, + "dependencies": { + "@angular-devkit/core": { + "version": "14.0.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.0.7.tgz", + "integrity": "sha512-XBqK2OMVKkV1Ltkh4aBsoHoDJQlins5a6qa/ZMjW4reYx90qLERs8ZfeWlRUWhvn2/ohx4aPq77jwSR5avp/Cw==", + "dev": true, + "requires": { + "ajv": "8.11.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.0.0", + "rxjs": "6.6.7", + "source-map": "0.7.3" + } + }, + "jsonc-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "dev": true + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular/animations": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-14.2.5.tgz", + "integrity": "sha512-4BhR9jSjgIwoK/alu7FSwSU5SxISMVFBAl/4cEYchfCqnflMNkZ8WwRVKTQjyeuYW5KtQTw9jRNp4tGK1YQWYw==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/cli": { + "version": "14.0.7", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-14.0.7.tgz", + "integrity": "sha512-tABt1EDwBHm0ngsutdkXXWgPgHzapGLC7rSPHXStMc24ngViFZpXGzBCpompjHvXNt6bjklmJmuRvjS6+ktBZA==", + "dev": true, + "requires": { + "@angular-devkit/architect": "0.1400.7", + "@angular-devkit/core": "14.0.7", + "@angular-devkit/schematics": "14.0.7", + "@schematics/angular": "14.0.7", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.1", + "debug": "4.3.4", + "ini": "3.0.0", + "inquirer": "8.2.4", + "jsonc-parser": "3.0.0", + "npm-package-arg": "9.0.2", + "npm-pick-manifest": "7.0.1", + "open": "8.4.0", + "ora": "5.4.1", + "pacote": "13.3.0", + "resolve": "1.22.0", + "semver": "7.3.7", + "symbol-observable": "4.0.0", + "uuid": "8.3.2", + "yargs": "17.4.1" + }, + "dependencies": { + "@angular-devkit/architect": { + "version": "0.1400.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1400.7.tgz", + "integrity": "sha512-8dv/Ql86dHajsHYjjr5jvpiV7uXWbt7Mz4K/rGiOi+zzDNKPcZcuCejulWhOySDcCPjT/an47Qcwr+awL4Wr4g==", + "dev": true, + "requires": { + "@angular-devkit/core": "14.0.7", + "rxjs": "6.6.7" + } + }, + "@angular-devkit/core": { + "version": "14.0.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.0.7.tgz", + "integrity": "sha512-XBqK2OMVKkV1Ltkh4aBsoHoDJQlins5a6qa/ZMjW4reYx90qLERs8ZfeWlRUWhvn2/ohx4aPq77jwSR5avp/Cw==", + "dev": true, + "requires": { + "ajv": "8.11.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.0.0", + "rxjs": "6.6.7", + "source-map": "0.7.3" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "jsonc-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "dev": true + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@angular/common": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.2.5.tgz", + "integrity": "sha512-v2fIK6imfMkUvYNjZQO+drE39QO3eSS95Yy7UN+6inb47DkAfzx6hipA9zKrMENjsS3kDv1d7cgDHE7WuOCzIw==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/compiler": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-14.2.5.tgz", + "integrity": "sha512-L7d2/D6o9wlB2ugqRYpev6a8JntqS+7lF2o6z8y7RR2YAlAu71nq0BDsQez4/aSCK3HnDq0yhEnns7vcmOq/jA==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/compiler-cli": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-14.2.5.tgz", + "integrity": "sha512-3GYzTPw96TfJjw7Aso+f+uN6VFBWedqRATUQ6v+BAEyZIboirdLI1JQFOcCfuKWUM2B48RW+pdIduZmG3ckotA==", + "dev": true, + "requires": { + "@babel/core": "^7.17.2", + "chokidar": "^3.0.0", + "convert-source-map": "^1.5.1", + "dependency-graph": "^0.11.0", + "magic-string": "^0.26.0", + "reflect-metadata": "^0.1.2", + "semver": "^7.0.0", + "sourcemap-codec": "^1.4.8", + "tslib": "^2.3.0", + "yargs": "^17.2.1" + } + }, + "@angular/core": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.2.5.tgz", + "integrity": "sha512-Ok78Abq0puMGlolvNVzKFvsX7ePDkyxpZzztDzXDdRA4x4o6bAuuDG9Y7Wab2+wsdY6NktO+dFQjq1UBWClgSg==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/forms": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-14.2.5.tgz", + "integrity": "sha512-aMH5Vrftny0KF0XzWQIGfHoI0LVQ2aatpWzdUWiUqBeX/Q+ucmxeP5rZyKtUsi0flETWxdRZSBTjbXZ3dsIcTA==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/platform-browser": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-14.2.5.tgz", + "integrity": "sha512-FDZm23N9veSEouQX1YuZUjv7Nillroi+v0VbN1x5iPpFZEudaoZYT3A7bpJwdlxUx/4rGS0caaXNhN3CowtIeQ==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/platform-browser-dynamic": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-14.2.5.tgz", + "integrity": "sha512-7W8oLs8YEGRr8izgUlpHgBfg3vUb5H0yicTHJY4zIqHJJbG1rTl46CjULaMjYM/FWcS8o7y6XJJcHx0c7pKNsw==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/router": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-14.2.5.tgz", + "integrity": "sha512-AUHcr9Lln7emJ/aete08UoqWQFZOLH1MhuP78r2pixvnNiZ9C8hcevX1rGGax0Po/Gy4PSJ4wnFhZPgifqCguQ==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@assemblyscript/loader": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", + "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==", + "dev": true + }, + "@auth0/angular-jwt": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@auth0/angular-jwt/-/angular-jwt-5.1.0.tgz", + "integrity": "sha512-EAQoNKPQSZYphcX6FnY2e7xQpD4ZdHQ1DbHq/m+G1U1qA60m3XnhdjPPfu+blVHARlxEbRzWXc48UOVrnMsrZw==", + "requires": { + "tslib": "^2.0.0" + } + }, + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/compat-data": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.4.tgz", + "integrity": "sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==", + "dev": true + }, + "@babel/core": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.10.tgz", + "integrity": "sha512-JQM6k6ENcBFKVtWvLavlvi/mPcpYZ3+R+2EySDEMSMbp7Mn4FexlbbJVrx2R7Ijhr01T8gyqrOaABWIOgxeUyw==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.1.0", + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.18.10", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.10", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.10", + "@babel/types": "^7.18.10", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.18.12", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz", + "integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==", + "dev": true, + "requires": { + "@babel/types": "^7.18.10", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", + "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.18.6", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.19.3", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.19.3.tgz", + "integrity": "sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.19.3", + "@babel/helper-validator-option": "^7.18.6", + "browserslist": "^4.21.3", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.19.0.tgz", + "integrity": "sha512-NRz8DwF4jT3UfrmUoZjd0Uph9HQnP30t7Ash+weACcyNkiYTywpIjDBgReJMKgr+n86sn2nPVVmJ28Dm053Kqw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.19.0.tgz", + "integrity": "sha512-htnV+mHX32DF81amCDrwIDr8nrp1PTm+3wfBN9/v8QJOLEioOCOG7qNyq0nHeFiWbT3Eb7gsPwEmV64UCQ1jzw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "regexpu-core": "^5.1.0" + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz", + "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2", + "semver": "^6.1.2" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/helper-environment-visitor": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "dev": true + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz", + "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-function-name": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz", + "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==", + "dev": true, + "requires": { + "@babel/template": "^7.18.10", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", + "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", + "dev": true, + "requires": { + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-module-imports": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", + "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-module-transforms": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.19.0.tgz", + "integrity": "sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/helper-validator-identifier": "^7.18.6", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", + "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz", + "integrity": "sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==", + "dev": true + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-replace-supers": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.19.1.tgz", + "integrity": "sha512-T7ahH7wV0Hfs46SFh5Jz3s0B6+o8g3c+7TMxu7xKfmHikg7EAZ3I2Qk9LFhjxXq8sL7UkP5JflezNwoZa8WvWw==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/traverse": "^7.19.1", + "@babel/types": "^7.19.0" + } + }, + "@babel/helper-simple-access": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.19.4.tgz", + "integrity": "sha512-f9Xq6WqBFqaDfbCzn2w85hwklswz5qsKlh7f08w4Y9yhJHpnNC0QemtSkK5YyOY8kPGvyiwdzZksGUhnGdaUIg==", + "dev": true, + "requires": { + "@babel/types": "^7.19.4" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", + "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", + "dev": true, + "requires": { + "@babel/types": "^7.18.9" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", + "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "dev": true, + "requires": { + "@babel/types": "^7.18.6" + } + }, + "@babel/helper-string-parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", + "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", + "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==", + "dev": true + }, + "@babel/helper-wrap-function": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.19.0.tgz", + "integrity": "sha512-txX8aN8CZyYGTwcLhlk87KRqncAzhh5TpQamZUa0/u3an36NtDpUP6bQgBCBcLeBs09R/OwQu3OjK0k/HwfNDg==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.19.0", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.0", + "@babel/types": "^7.19.0" + } + }, + "@babel/helpers": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.19.4.tgz", + "integrity": "sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw==", + "dev": true, + "requires": { + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.19.4", + "@babel/types": "^7.19.4" + } + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.4.tgz", + "integrity": "sha512-qpVT7gtuOLjWeDTKLkJ6sryqLliBaFpAtGeqw5cs5giLldvh+Ch0plqnUMKoVAUS6ZEueQQiZV+p5pxtPitEsA==", + "dev": true + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz", + "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" + } + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.10.tgz", + "integrity": "sha512-1mFuY2TOsR1hxbjCo4QL+qlIjV07p4H4EUYw2J/WCqsvFV6V9X9z9YhXbWndc/4fw+hYGlDT7egYxliMp5O6Ew==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-remap-async-to-generator": "^7.18.9", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz", + "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-class-static-block": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.18.6.tgz", + "integrity": "sha512-+I3oIiNxrCpup3Gi8n5IGMwj0gOCAjcJUSQEcotNnCCPMEnixawOQ+KeJPlgfjzx+FKQ1QSyZOWe7wmoJp7vhw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz", + "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz", + "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz", + "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz", + "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.19.4.tgz", + "integrity": "sha512-wHmj6LDxVDnL+3WhXteUBaoM1aVILZODAUjg11kHqG4cOlfgMQGxw6aCgvrXrmaJR3Bn14oZhImyCPZzRpC93Q==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.19.4", + "@babel/helper-compilation-targets": "^7.19.3", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.18.8" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz", + "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.18.6.tgz", + "integrity": "sha512-9Rysx7FOctvT5ouj5JODjAFAkgGoudQuLPamZb0v1TGLpapdNaftzifU8NTWQm0IRjqoYypdrSmyWgkocDQ8Dw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz", + "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.18.6.tgz", + "integrity": "sha512-/DU3RXad9+bZwrgWJQKbr39gYbJpLJHezqEzRzi/BHRlJ9zsQb4CK2CA/5apllXNomwA1qHwzvHl+AdEmC5krQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.18.6.tgz", + "integrity": "sha512-9S9X9RUefzrsHZmKMbDXxweEH+YlE8JJEuat9FdvW9Qh1cw7W64jELCtWNkPBPX5En45uy28KGvA/AySqUh8CQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.18.6.tgz", + "integrity": "sha512-ARE5wZLKnTgPW7/1ftQmSi1CmkqqHo2DNmtztFhvgtOWSDfq0Cq9/9L+KnZNYSNrydBekhW3rwShduf59RoXag==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-remap-async-to-generator": "^7.18.6" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz", + "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.19.4.tgz", + "integrity": "sha512-934S2VLLlt2hRJwPf4MczaOr4hYF0z+VKPwqTNxyKX7NthTiPfhuKFWQZHXRM0vh/wo/VyXB3s4bZUNA08l+tQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.19.0.tgz", + "integrity": "sha512-YfeEE9kCjqTS9IitkgfJuxjcEtLUHMqa8yUJ6zdz8vR7hKuo6mOy2C05P0F1tdMmDCeuyidKnlrw/iTppHcr2A==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.18.6", + "@babel/helper-compilation-targets": "^7.19.0", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-optimise-call-expression": "^7.18.6", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-replace-supers": "^7.18.9", + "@babel/helper-split-export-declaration": "^7.18.6", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.19.4.tgz", + "integrity": "sha512-t0j0Hgidqf0aM86dF8U+vXYReUgJnlv4bZLsyoPnwZNrGY+7/38o8YjaELrvHeVfTZao15kjR0PVv0nju2iduA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz", + "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz", + "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", + "dev": true, + "requires": { + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz", + "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.18.6.tgz", + "integrity": "sha512-Pra5aXsmTsOnjM3IajS8rTaLCy++nGM4v3YR4esk5PCsyg9z8NA5oQLwxzMUtDBd8F+UmVza3VxoAaWCbzH1rg==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.18.6.tgz", + "integrity": "sha512-Qfv2ZOWikpvmedXQJDSbxNqy7Xr/j2Y8/KfijM0iJyKkBTmWuvCA1yeH1yDM7NJhBW/2aXxeucLj6i80/LAJ/Q==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-simple-access": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.19.0.tgz", + "integrity": "sha512-x9aiR0WXAWmOWsqcsnrzGR+ieaTMVyGyffPVA7F8cXAGt/UxefYv6uSHZLkAFChN5M5Iy1+wjE+xJuPt22H39A==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-module-transforms": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-validator-identifier": "^7.18.6", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz", + "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.19.1.tgz", + "integrity": "sha512-oWk9l9WItWBQYS4FgXD4Uyy5kq898lvkXpXQxoJEY1RnvPk4R/Dvu2ebXU9q8lP+rlMwUQTFf2Ok6d78ODa0kw==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.19.0", + "@babel/helper-plugin-utils": "^7.19.0" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz", + "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz", + "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.6" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz", + "integrity": "sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz", + "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.18.6.tgz", + "integrity": "sha512-poqRI2+qiSdeldcz4wTSTXBRryoq3Gc70ye7m7UD5Ww0nE29IXqMl6r7Nd15WBgRd74vloEMlShtH6CKxVzfmQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6", + "regenerator-transform": "^0.15.0" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz", + "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.10.tgz", + "integrity": "sha512-q5mMeYAdfEbpBAgzl7tBre/la3LeCxmDO1+wMXRdPWbcoMjR3GiXlCLk7JBZVVye0bqTGNMbt0yYVXX1B1jEWQ==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz", + "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.19.0.tgz", + "integrity": "sha512-RsuMk7j6n+r752EtzyScnWkQyuJdli6LdO5Klv8Yx0OfPVTcQkIUfS8clx5e9yHXzlnhOZF3CbQ8C2uP5j074w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.19.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz", + "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.18.9" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz", + "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/preset-env": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.10.tgz", + "integrity": "sha512-wVxs1yjFdW3Z/XkNfXKoblxoHgbtUF7/l3PvvP4m02Qz9TZ6uZGxRVYjSQeR87oQmHco9zWitW5J82DJ7sCjvA==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.18.8", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-validator-option": "^7.18.6", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.18.10", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/plugin-proposal-class-static-block": "^7.18.6", + "@babel/plugin-proposal-dynamic-import": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", + "@babel/plugin-proposal-json-strings": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", + "@babel/plugin-proposal-numeric-separator": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.18.9", + "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "@babel/plugin-proposal-private-property-in-object": "^7.18.6", + "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", + "@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-import-assertions": "^7.18.6", + "@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.18.6", + "@babel/plugin-transform-async-to-generator": "^7.18.6", + "@babel/plugin-transform-block-scoped-functions": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.18.9", + "@babel/plugin-transform-classes": "^7.18.9", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.18.9", + "@babel/plugin-transform-dotall-regex": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", + "@babel/plugin-transform-exponentiation-operator": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", + "@babel/plugin-transform-member-expression-literals": "^7.18.6", + "@babel/plugin-transform-modules-amd": "^7.18.6", + "@babel/plugin-transform-modules-commonjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.18.9", + "@babel/plugin-transform-modules-umd": "^7.18.6", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.18.6", + "@babel/plugin-transform-new-target": "^7.18.6", + "@babel/plugin-transform-object-super": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", + "@babel/plugin-transform-property-literals": "^7.18.6", + "@babel/plugin-transform-regenerator": "^7.18.6", + "@babel/plugin-transform-reserved-words": "^7.18.6", + "@babel/plugin-transform-shorthand-properties": "^7.18.6", + "@babel/plugin-transform-spread": "^7.18.9", + "@babel/plugin-transform-sticky-regex": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", + "@babel/plugin-transform-unicode-regex": "^7.18.6", + "@babel/preset-modules": "^0.1.5", + "@babel/types": "^7.18.10", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", + "core-js-compat": "^3.22.1", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "@babel/preset-modules": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", + "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", + "dev": true, + "requires": { + "@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/runtime": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", + "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" + } + }, + "@babel/traverse": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.4.tgz", + "integrity": "sha512-w3K1i+V5u2aJUOXBFFC5pveFLmtq1s3qcdDNC2qRI6WPBQIDaKFqXxDEqDO/h1dQ3HjsZoZMyIy6jGLq0xtw+g==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.18.6", + "@babel/generator": "^7.19.4", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.19.0", + "@babel/helper-hoist-variables": "^7.18.6", + "@babel/helper-split-export-declaration": "^7.18.6", + "@babel/parser": "^7.19.4", + "@babel/types": "^7.19.4", + "debug": "^4.1.0", + "globals": "^11.1.0" + }, + "dependencies": { + "@babel/generator": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.4.tgz", + "integrity": "sha512-5T2lY5vXqS+5UEit/5TwcIUeCnwgCljcF8IQRT6XRQPBrvLeq5V8W+URv+GvwoF3FP8tkhp++evVyDzkDGzNmA==", + "dev": true, + "requires": { + "@babel/types": "^7.19.4", + "@jridgewell/gen-mapping": "^0.3.2", + "jsesc": "^2.5.1" + } + }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/types": { + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.4.tgz", + "integrity": "sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.19.4", + "@babel/helper-validator-identifier": "^7.19.1", + "to-fast-properties": "^2.0.0" + } + }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true + }, + "@csstools/postcss-cascade-layers": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.1.1.tgz", + "integrity": "sha512-+KdYrpKC5TgomQr2DlZF4lDEpHcoxnj5IGddYYfBWJAKfj1JtuHUIqMa+E1pJJ+z3kvDViWMqyqPlG4Ja7amQA==", + "dev": true, + "requires": { + "@csstools/selector-specificity": "^2.0.2", + "postcss-selector-parser": "^6.0.10" + } + }, + "@csstools/postcss-color-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-color-function/-/postcss-color-function-1.1.1.tgz", + "integrity": "sha512-Bc0f62WmHdtRDjf5f3e2STwRAl89N2CLb+9iAwzrv4L2hncrbDwnQD9PCq0gtAt7pOI2leIV08HIBUd4jxD8cw==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-font-format-keywords": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-font-format-keywords/-/postcss-font-format-keywords-1.0.1.tgz", + "integrity": "sha512-ZgrlzuUAjXIOc2JueK0X5sZDjCtgimVp/O5CEqTcs5ShWBa6smhWYbS0x5cVc/+rycTDbjjzoP0KTDnUneZGOg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-hwb-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-hwb-function/-/postcss-hwb-function-1.0.2.tgz", + "integrity": "sha512-YHdEru4o3Rsbjmu6vHy4UKOXZD+Rn2zmkAmLRfPet6+Jz4Ojw8cbWxe1n42VaXQhD3CQUXXTooIy8OkVbUcL+w==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-ic-unit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-ic-unit/-/postcss-ic-unit-1.0.1.tgz", + "integrity": "sha512-Ot1rcwRAaRHNKC9tAqoqNZhjdYBzKk1POgWfhN4uCOE47ebGcLRqXjKkApVDpjifL6u2/55ekkpnFcp+s/OZUw==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-is-pseudo-class": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@csstools/postcss-is-pseudo-class/-/postcss-is-pseudo-class-2.0.7.tgz", + "integrity": "sha512-7JPeVVZHd+jxYdULl87lvjgvWldYu+Bc62s9vD/ED6/QTGjy0jy0US/f6BG53sVMTBJ1lzKZFpYmofBN9eaRiA==", + "dev": true, + "requires": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + } + }, + "@csstools/postcss-nested-calc": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-nested-calc/-/postcss-nested-calc-1.0.0.tgz", + "integrity": "sha512-JCsQsw1wjYwv1bJmgjKSoZNvf7R6+wuHDAbi5f/7MbFhl2d/+v+TvBTU4BJH3G1X1H87dHl0mh6TfYogbT/dJQ==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-normalize-display-values": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-normalize-display-values/-/postcss-normalize-display-values-1.0.1.tgz", + "integrity": "sha512-jcOanIbv55OFKQ3sYeFD/T0Ti7AMXc9nM1hZWu8m/2722gOTxFg7xYu4RDLJLeZmPUVQlGzo4jhzvTUq3x4ZUw==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-oklab-function": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-oklab-function/-/postcss-oklab-function-1.1.1.tgz", + "integrity": "sha512-nJpJgsdA3dA9y5pgyb/UfEzE7W5Ka7u0CX0/HIMVBNWzWemdcTH3XwANECU6anWv/ao4vVNLTMxhiPNZsTK6iA==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-progressive-custom-properties": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-progressive-custom-properties/-/postcss-progressive-custom-properties-1.3.0.tgz", + "integrity": "sha512-ASA9W1aIy5ygskZYuWams4BzafD12ULvSypmaLJT2jvQ8G0M3I8PRQhC0h7mG0Z3LI05+agZjqSR9+K9yaQQjA==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-stepped-value-functions": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@csstools/postcss-stepped-value-functions/-/postcss-stepped-value-functions-1.0.1.tgz", + "integrity": "sha512-dz0LNoo3ijpTOQqEJLY8nyaapl6umbmDcgj4AD0lgVQ572b2eqA1iGZYTTWhrcrHztWDDRAX2DGYyw2VBjvCvQ==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-text-decoration-shorthand": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@csstools/postcss-text-decoration-shorthand/-/postcss-text-decoration-shorthand-1.0.0.tgz", + "integrity": "sha512-c1XwKJ2eMIWrzQenN0XbcfzckOLLJiczqy+YvfGmzoVXd7pT9FfObiSEfzs84bpE/VqfpEuAZ9tCRbZkZxxbdw==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-trigonometric-functions": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-trigonometric-functions/-/postcss-trigonometric-functions-1.0.2.tgz", + "integrity": "sha512-woKaLO///4bb+zZC2s80l+7cm07M7268MsyG3M0ActXXEFi6SuhvriQYcb58iiKGbjwwIU7n45iRLEHypB47Og==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "@csstools/postcss-unset-value": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@csstools/postcss-unset-value/-/postcss-unset-value-1.0.2.tgz", + "integrity": "sha512-c8J4roPBILnelAsdLr4XOAR/GsTm0GJi4XpcfvoWk3U6KiTCqiFYc63KhRMQQX35jYMp4Ao8Ij9+IZRgMfJp1g==", + "dev": true, + "requires": {} + }, + "@csstools/selector-specificity": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz", + "integrity": "sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg==", + "dev": true, + "requires": {} + }, + "@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true + }, + "@esbuild/linux-loong64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.5.tgz", + "integrity": "sha512-UHkDFCfSGTuXq08oQltXxSZmH1TXyWsL+4QhZDWvvLl6mEJQqk3u7/wq1LjhrrAXYIllaTtRSzUXl4Olkf2J8A==", + "dev": true, + "optional": true + }, + "@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "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": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.16", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.16.tgz", + "integrity": "sha512-LCQ+NeThyJ4k1W2d+vIKdxuSt9R3pQSZ4P92m7EakaYuXcVWbHuT5bjNcqLd4Rdgi6xYWYDvBJZJLZSLanjDcA==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", + "dev": true + }, + "@microsoft/signalr": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-6.0.9.tgz", + "integrity": "sha512-DGVYe3ycT2PfRU7m3xCbv1HjhvClKl2VB1HyFlvf8SqBGXz3Cx+oalNWGYrGIgADA6Q2xaB4GaDmDdprTa2U0Q==", + "requires": { + "abort-controller": "^3.0.0", + "eventsource": "^1.0.7", + "fetch-cookie": "^0.11.0", + "node-fetch": "^2.6.7", + "ws": "^7.4.5" + }, + "dependencies": { + "ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "requires": {} + } + } + }, + "@ngtools/webpack": { + "version": "14.2.5", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.5.tgz", + "integrity": "sha512-Thwq1WyOOq1PIWMcjAAqKI1hbvGC0ywxbNoDadOlWpEFm6k0dvXC6Zm9lnVkePjxlPfagvbnv55+Lv9Vmygc1g==", + "dev": true, + "requires": {} + }, + "@ngx-translate/core": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/core/-/core-14.0.0.tgz", + "integrity": "sha512-UevdwNCXMRCdJv//0kC8h2eSfmi02r29xeE8E9gJ1Al4D4jEJ7eiLPdjslTMc21oJNGguqqWeEVjf64SFtvw2w==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@ngx-translate/http-loader": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@ngx-translate/http-loader/-/http-loader-7.0.0.tgz", + "integrity": "sha512-j+NpXXlcGVdyUNyY/qsJrqqeAdJdizCd+GKh3usXExSqy1aE9866jlAIL+xrfDU4w+LiMoma5pgE4emvFebZmA==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@npmcli/fs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", + "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "dev": true, + "requires": { + "@gar/promisify": "^1.1.3", + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-3.0.2.tgz", + "integrity": "sha512-CAcd08y3DWBJqJDpfuVL0uijlq5oaXaOJEKHKc4wqrjd00gkvTZB+nFuLn+doOOKddaQS9JfqtNoFCO2LCvA3w==", + "dev": true, + "requires": { + "@npmcli/promise-spawn": "^3.0.0", + "lru-cache": "^7.4.4", + "mkdirp": "^1.0.4", + "npm-pick-manifest": "^7.0.0", + "proc-log": "^2.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^2.0.2" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "@npmcli/installed-package-contents": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", + "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "dev": true, + "requires": { + "npm-bundled": "^1.1.1", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "@npmcli/move-file": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", + "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "@npmcli/node-gyp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz", + "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", + "dev": true + }, + "@npmcli/promise-spawn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-3.0.0.tgz", + "integrity": "sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g==", + "dev": true, + "requires": { + "infer-owner": "^1.0.4" + } + }, + "@npmcli/run-script": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-3.0.3.tgz", + "integrity": "sha512-ZXL6qgC5NjwfZJ2nET+ZSLEz/PJgJ/5CU90C2S66dZY4Jw73DasS4ZCXuy/KHWYP0imjJ4VtA+Gebb5BxxKp9Q==", + "dev": true, + "requires": { + "@npmcli/node-gyp": "^2.0.0", + "@npmcli/promise-spawn": "^3.0.0", + "node-gyp": "^8.4.1", + "read-package-json-fast": "^2.0.3" + } + }, + "@schematics/angular": { + "version": "14.0.7", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-14.0.7.tgz", + "integrity": "sha512-I0v1gNFpm9ReL/hUzwjjOa+hk0qvlXv/vjITAWnlUV5dba6FZxzwsrTGsGO6t5XMNsm6QtwpDYDRdy9uy/n/1g==", + "dev": true, + "requires": { + "@angular-devkit/core": "14.0.7", + "@angular-devkit/schematics": "14.0.7", + "jsonc-parser": "3.0.0" + }, + "dependencies": { + "@angular-devkit/core": { + "version": "14.0.7", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.0.7.tgz", + "integrity": "sha512-XBqK2OMVKkV1Ltkh4aBsoHoDJQlins5a6qa/ZMjW4reYx90qLERs8ZfeWlRUWhvn2/ohx4aPq77jwSR5avp/Cw==", + "dev": true, + "requires": { + "ajv": "8.11.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.0.0", + "rxjs": "6.6.7", + "source-map": "0.7.3" + } + }, + "jsonc-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz", + "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==", + "dev": true + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", + "dev": true + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/bonjour": { + "version": "3.5.10", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz", + "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/connect-history-api-fallback": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz", + "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==", + "dev": true, + "requires": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "dev": true + }, + "@types/cors": { + "version": "2.8.12", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", + "integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw==", + "dev": true + }, + "@types/eslint": { + "version": "8.4.6", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.6.tgz", + "integrity": "sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g==", + "dev": true, + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.4", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz", + "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==", + "dev": true, + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "@types/express": { + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.14.tgz", + "integrity": "sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.31", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.31.tgz", + "integrity": "sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/http-proxy": { + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", + "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/jasmine": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-4.0.3.tgz", + "integrity": "sha512-Opp1LvvEuZdk8fSSvchK2mZwhVrsNT0JgJE9Di6MjnaIpmEXM8TLCPPrVtNTYh8+5MPdY8j9bAHMu2SSfwpZJg==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true + }, + "@types/node": { + "version": "18.8.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz", + "integrity": "sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==", + "dev": true + }, + "@types/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "dev": true + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true + }, + "@types/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dev": true, + "requires": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "@types/sockjs": { + "version": "0.3.33", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", + "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/ws": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", + "dev": true, + "requires": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", + "dev": true, + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", + "dev": true, + "requires": { + "@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": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", + "dev": true, + "requires": { + "@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": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", + "dev": true, + "requires": { + "@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": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", + "dev": true, + "requires": { + "@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": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", + "dev": true, + "requires": { + "@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": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "requires": { + "event-target-shim": "^5.0.0" + } + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz", + "integrity": "sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==", + "dev": true + }, + "acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "requires": {} + }, + "adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "dependencies": { + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true + } + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dev": true, + "requires": { + "ajv": "^8.0.0" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "autoprefixer": { + "version": "10.4.12", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.12.tgz", + "integrity": "sha512-WrCGV9/b97Pa+jtwf5UGaRjgQIg7OK3D06GnoYoZNcG1Xb8Gt3EfuKjlhh9i/VtT16g6PYjZ69jdJ2g8FxSC4Q==", + "dev": true, + "requires": { + "browserslist": "^4.21.4", + "caniuse-lite": "^1.0.30001407", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + } + }, + "babel-loader": { + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", + "dev": true, + "requires": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^2.0.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "requires": { + "@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-polyfill-corejs2": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz", + "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.3", + "semver": "^6.1.1" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz", + "integrity": "sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.2", + "core-js-compat": "^3.21.0" + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz", + "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==", + "dev": true, + "requires": { + "@babel/helper-define-polyfill-provider": "^0.3.3" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true + }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "body-parser": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "bonjour-service": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.0.14.tgz", + "integrity": "sha512-HIMbgLnk1Vqvs6B4Wq5ep7mxvj9sGz5d1JJyDNSGNIdA/w2MCz6GTjWTdjqOJV1bEPj+6IkxDvWNFKEBxNt4kQ==", + "dev": true, + "requires": { + "array-flatten": "^2.1.2", + "dns-equal": "^1.0.0", + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + } + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "requires": { + "semver": "^7.0.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true + }, + "cacache": { + "version": "16.1.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.2.tgz", + "integrity": "sha512-Xx+xPlfCZIUHagysjjOAje9nRo8pRDczQCcXb4J2O0BLtH+xeVue6ba4y1kfJfQMAnM2mkcoMIAyOctlaRGWYA==", + "dev": true, + "requires": { + "@npmcli/fs": "^2.1.0", + "@npmcli/move-file": "^2.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "glob": "^8.0.1", + "infer-owner": "^1.0.4", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "mkdirp": "^1.0.4", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11", + "unique-filename": "^1.1.1" + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001418", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz", + "integrity": "sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.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" + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dev": true, + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", + "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", + "dev": true + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "dev": true + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true + }, + "colorette": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dev": true, + "requires": { + "safe-buffer": "5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "convert-source-map": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", + "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "dev": true + }, + "copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dev": true, + "requires": { + "is-what": "^3.14.1" + } + }, + "copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dev": true, + "requires": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "core-js-compat": { + "version": "3.25.5", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.25.5.tgz", + "integrity": "sha512-ovcyhs2DEBUIE0MGEKHP4olCUW/XYte3Vroyxuh38rD1wAO4dHohsovUC4eAOuzFxE6b+RXvBU3UZ9o0YhUTkA==", + "dev": true, + "requires": { + "browserslist": "^4.21.4" + } + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dev": true, + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "cosmiconfig": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", + "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", + "dev": true, + "requires": { + "@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" + } + }, + "critters": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz", + "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "css-select": "^4.2.0", + "parse5": "^6.0.1", + "parse5-htmlparser2-tree-adapter": "^6.0.1", + "postcss": "^8.3.7", + "pretty-bytes": "^5.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "css-blank-pseudo": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/css-blank-pseudo/-/css-blank-pseudo-3.0.3.tgz", + "integrity": "sha512-VS90XWtsHGqoM0t4KpH053c4ehxZ2E6HtGI7x68YFV0pTo/QmkV/YFA+NnlvK8guxZVNWGQhVNJGC39Q8XF4OQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "css-has-pseudo": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/css-has-pseudo/-/css-has-pseudo-3.0.4.tgz", + "integrity": "sha512-Vse0xpR1K9MNlp2j5w1pgWIJtm1a8qS0JwS9goFYcImjlHEmywP9VUF05aGBXzGpDJF86QXk4L0ypBmwPhGArw==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "css-loader": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", + "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", + "dev": true, + "requires": { + "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-prefers-color-scheme": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/css-prefers-color-scheme/-/css-prefers-color-scheme-6.0.3.tgz", + "integrity": "sha512-4BqMbZksRkJQx2zAjrokiGMd07RqOa2IxIrrN10lyBe9xhn9DEvjUK79J6jkeiv9D9hQFXKb6g1jwU62jziJZA==", + "dev": true, + "requires": {} + }, + "css-select": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", + "domutils": "^2.8.0", + "nth-check": "^2.0.1" + } + }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true + }, + "cssdb": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.0.1.tgz", + "integrity": "sha512-pT3nzyGM78poCKLAEy2zWIVX2hikq6dIrjuZzLV98MumBg+xMTNYfHx7paUlfiRTgg91O/vR889CIf+qiv79Rw==", + "dev": true + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", + "dev": true + }, + "date-format": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dev": true, + "requires": { + "execa": "^5.0.0" + } + }, + "defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "dev": true + }, + "define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "dependency-graph": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", + "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", + "dev": true + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true + }, + "di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", + "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", + "dev": true + }, + "dns-packet": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz", + "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==", + "dev": true, + "requires": { + "@leichtgewicht/ip-codec": "^2.0.1" + } + }, + "dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", + "dev": true, + "requires": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "dom-serializer": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.2.0", + "entities": "^2.0.0" + } + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true + }, + "domhandler": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", + "dev": true, + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz", + "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==", + "dev": true, + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true + }, + "electron-to-chromium": { + "version": "1.4.276", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.276.tgz", + "integrity": "sha512-EpuHPqu8YhonqLBXHoU6hDJCD98FCe6KDoet3/gY1qsQ6usjJoHqBH2YIVs8FXaAtHwVL8Uqa/fsYao/vq9VWQ==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "dev": true + }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "engine.io": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.2.0.tgz", + "integrity": "sha512-4KzwW3F3bk+KlzSOY57fj/Jx6LyRQ1nbcyIadehl+AnXjKT7gDO0ORdRi/84ixvMKTym6ZKuxvbzN62HDDU1Lg==", + "dev": true, + "requires": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.2.3" + } + }, + "engine.io-parser": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", + "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==", + "dev": true + }, + "enhanced-resolve": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA==", + "dev": true + }, + "entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true + }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "dev": true, + "optional": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, + "esbuild": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.5.tgz", + "integrity": "sha512-VSf6S1QVqvxfIsSKb3UKr3VhUCis7wgDbtF4Vd9z84UJr05/Sp2fRKmzC+CSPG/dNAPPJZ0BTBLTT1Fhd6N9Gg==", + "dev": true, + "optional": true, + "requires": { + "@esbuild/linux-loong64": "0.15.5", + "esbuild-android-64": "0.15.5", + "esbuild-android-arm64": "0.15.5", + "esbuild-darwin-64": "0.15.5", + "esbuild-darwin-arm64": "0.15.5", + "esbuild-freebsd-64": "0.15.5", + "esbuild-freebsd-arm64": "0.15.5", + "esbuild-linux-32": "0.15.5", + "esbuild-linux-64": "0.15.5", + "esbuild-linux-arm": "0.15.5", + "esbuild-linux-arm64": "0.15.5", + "esbuild-linux-mips64le": "0.15.5", + "esbuild-linux-ppc64le": "0.15.5", + "esbuild-linux-riscv64": "0.15.5", + "esbuild-linux-s390x": "0.15.5", + "esbuild-netbsd-64": "0.15.5", + "esbuild-openbsd-64": "0.15.5", + "esbuild-sunos-64": "0.15.5", + "esbuild-windows-32": "0.15.5", + "esbuild-windows-64": "0.15.5", + "esbuild-windows-arm64": "0.15.5" + } + }, + "esbuild-android-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.5.tgz", + "integrity": "sha512-dYPPkiGNskvZqmIK29OPxolyY3tp+c47+Fsc2WYSOVjEPWNCHNyqhtFqQadcXMJDQt8eN0NMDukbyQgFcHquXg==", + "dev": true, + "optional": true + }, + "esbuild-android-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.5.tgz", + "integrity": "sha512-YyEkaQl08ze3cBzI/4Cm1S+rVh8HMOpCdq8B78JLbNFHhzi4NixVN93xDrHZLztlocEYqi45rHHCgA8kZFidFg==", + "dev": true, + "optional": true + }, + "esbuild-darwin-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.5.tgz", + "integrity": "sha512-Cr0iIqnWKx3ZTvDUAzG0H/u9dWjLE4c2gTtRLz4pqOBGjfjqdcZSfAObFzKTInLLSmD0ZV1I/mshhPoYSBMMCQ==", + "dev": true, + "optional": true + }, + "esbuild-darwin-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.5.tgz", + "integrity": "sha512-WIfQkocGtFrz7vCu44ypY5YmiFXpsxvz2xqwe688jFfSVCnUsCn2qkEVDo7gT8EpsLOz1J/OmqjExePL1dr1Kg==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.5.tgz", + "integrity": "sha512-M5/EfzV2RsMd/wqwR18CELcenZ8+fFxQAAEO7TJKDmP3knhWSbD72ILzrXFMMwshlPAS1ShCZ90jsxkm+8FlaA==", + "dev": true, + "optional": true + }, + "esbuild-freebsd-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.5.tgz", + "integrity": "sha512-2JQQ5Qs9J0440F/n/aUBNvY6lTo4XP/4lt1TwDfHuo0DY3w5++anw+jTjfouLzbJmFFiwmX7SmUhMnysocx96w==", + "dev": true, + "optional": true + }, + "esbuild-linux-32": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.5.tgz", + "integrity": "sha512-gO9vNnIN0FTUGjvTFucIXtBSr1Woymmx/aHQtuU+2OllGU6YFLs99960UD4Dib1kFovVgs59MTXwpFdVoSMZoQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.5.tgz", + "integrity": "sha512-ne0GFdNLsm4veXbTnYAWjbx3shpNKZJUd6XpNbKNUZaNllDZfYQt0/zRqOg0sc7O8GQ+PjSMv9IpIEULXVTVmg==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.5.tgz", + "integrity": "sha512-wvAoHEN+gJ/22gnvhZnS/+2H14HyAxM07m59RSLn3iXrQsdS518jnEWRBnJz3fR6BJa+VUTo0NxYjGaNt7RA7Q==", + "dev": true, + "optional": true + }, + "esbuild-linux-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.5.tgz", + "integrity": "sha512-7EgFyP2zjO065XTfdCxiXVEk+f83RQ1JsryN1X/VSX2li9rnHAt2swRbpoz5Vlrl6qjHrCmq5b6yxD13z6RheA==", + "dev": true, + "optional": true + }, + "esbuild-linux-mips64le": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.5.tgz", + "integrity": "sha512-KdnSkHxWrJ6Y40ABu+ipTZeRhFtc8dowGyFsZY5prsmMSr1ZTG9zQawguN4/tunJ0wy3+kD54GaGwdcpwWAvZQ==", + "dev": true, + "optional": true + }, + "esbuild-linux-ppc64le": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.5.tgz", + "integrity": "sha512-QdRHGeZ2ykl5P0KRmfGBZIHmqcwIsUKWmmpZTOq573jRWwmpfRmS7xOhmDHBj9pxv+6qRMH8tLr2fe+ZKQvCYw==", + "dev": true, + "optional": true + }, + "esbuild-linux-riscv64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.5.tgz", + "integrity": "sha512-p+WE6RX+jNILsf+exR29DwgV6B73khEQV0qWUbzxaycxawZ8NE0wA6HnnTxbiw5f4Gx9sJDUBemh9v49lKOORA==", + "dev": true, + "optional": true + }, + "esbuild-linux-s390x": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.5.tgz", + "integrity": "sha512-J2ngOB4cNzmqLHh6TYMM/ips8aoZIuzxJnDdWutBw5482jGXiOzsPoEF4j2WJ2mGnm7FBCO4StGcwzOgic70JQ==", + "dev": true, + "optional": true + }, + "esbuild-netbsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.5.tgz", + "integrity": "sha512-MmKUYGDizYjFia0Rwt8oOgmiFH7zaYlsoQ3tIOfPxOqLssAsEgG0MUdRDm5lliqjiuoog8LyDu9srQk5YwWF3w==", + "dev": true, + "optional": true + }, + "esbuild-openbsd-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.5.tgz", + "integrity": "sha512-2mMFfkLk3oPWfopA9Plj4hyhqHNuGyp5KQyTT9Rc8hFd8wAn5ZrbJg+gNcLMo2yzf8Uiu0RT6G9B15YN9WQyMA==", + "dev": true, + "optional": true + }, + "esbuild-sunos-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.5.tgz", + "integrity": "sha512-2sIzhMUfLNoD+rdmV6AacilCHSxZIoGAU2oT7XmJ0lXcZWnCvCtObvO6D4puxX9YRE97GodciRGDLBaiC6x1SA==", + "dev": true, + "optional": true + }, + "esbuild-wasm": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.15.5.tgz", + "integrity": "sha512-lTJOEKekN/4JI/eOEq0wLcx53co2N6vaT/XjBz46D1tvIVoUEyM0o2K6txW6gEotf31szFD/J1PbxmnbkGlK9A==", + "dev": true + }, + "esbuild-windows-32": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.5.tgz", + "integrity": "sha512-e+duNED9UBop7Vnlap6XKedA/53lIi12xv2ebeNS4gFmu7aKyTrok7DPIZyU5w/ftHD4MUDs5PJUkQPP9xJRzg==", + "dev": true, + "optional": true + }, + "esbuild-windows-64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.5.tgz", + "integrity": "sha512-v+PjvNtSASHOjPDMIai9Yi+aP+Vwox+3WVdg2JB8N9aivJ7lyhp4NVU+J0MV2OkWFPnVO8AE/7xH+72ibUUEnw==", + "dev": true, + "optional": true + }, + "esbuild-windows-arm64": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.5.tgz", + "integrity": "sha512-Yz8w/D8CUPYstvVQujByu6mlf48lKmXkq6bkeSZZxTA626efQOJb26aDGLzmFWx6eg/FwrXgt6SZs9V8Pwy/aA==", + "dev": true, + "optional": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true + }, + "event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" + }, + "eventemitter-asyncresource": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz", + "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==", + "dev": true + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true + }, + "eventsource": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.2.tgz", + "integrity": "sha512-xAH3zWhgO2/3KIniEKYPr8plNSzlGINOUqYj0m0u7AB81iRw8b/3E73W6AuU+6klLbaSFmZnaETQ2lXPfAydrA==" + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "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" + } + }, + "express": { + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "dev": true, + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.1", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "requires": { + "@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": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fetch-cookie": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.11.0.tgz", + "integrity": "sha512-BQm7iZLFhMWFy5CZ/162sAGjBfdNWb7a8LEqqnzsHFhxT/X/SVj/z2t2nu3aJvjlbQkrAlTUApplPRjWyH4mhA==", + "requires": { + "tough-cookie": "^2.3.3 || ^3.0.1 || ^4.0.0" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + } + } + }, + "find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", + "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "dev": true + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true + }, + "fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "dev": true + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "fs-monkey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz", + "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + } + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "glob": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.0.3.tgz", + "integrity": "sha512-ull455NHSHI/Y1FqGaaYFaLGkNMMJbavMrEGFXG/PGrg6y7sutWHUHrz6gy6WEBH6akM1M414dWKCNs+IhKdiQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globby": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", + "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==", + "dev": true, + "requires": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + } + }, + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "hdr-histogram-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", + "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", + "dev": true, + "requires": { + "@assemblyscript/loader": "^0.10.1", + "base64-js": "^1.2.0", + "pako": "^1.0.3" + } + }, + "hdr-histogram-percentiles-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", + "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", + "dev": true + }, + "hosted-git-info": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.1.0.tgz", + "integrity": "sha512-Ek+QmMEqZF8XrbFdwoDjSbm7rT23pCgEMOJmz6GPk/s4yH//RQfNPArhIxbguNxROq/+5lNBwCDHMhA903Kx1Q==", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "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" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "html-entities": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", + "dev": true + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dev": true, + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "dependencies": { + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } + } + }, + "http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, + "http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "requires": { + "@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" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true, + "requires": {} + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "ignore-walk": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-5.0.1.tgz", + "integrity": "sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==", + "dev": true, + "requires": { + "minimatch": "^5.0.1" + } + }, + "image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "dev": true, + "optional": true + }, + "immutable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz", + "integrity": "sha512-oNkuqVTA8jqG1Q6c+UglTOD1xhC1BtjKI7XkCXRkZHrN5m18/XsnUp8Q89GkQO/z+0WjonSvl0FLhDYftp46nQ==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "ini": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-3.0.0.tgz", + "integrity": "sha512-TxYQaeNW/N8ymDvwAxPyRbhMBtnEwuvaTYpOQkFx1nSeusgezHniEc/l35Vo4iCq/mMiTJbpD7oYxN98hFlfmw==", + "dev": true + }, + "inquirer": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz", + "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==", + "dev": true, + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.1", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.21", + "mute-stream": "0.0.8", + "ora": "^5.4.1", + "run-async": "^2.4.0", + "rxjs": "^7.5.5", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + }, + "ipaddr.js": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz", + "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "dev": true + }, + "is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==", + "dev": true + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "requires": { + "is-docker": "^2.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "requires": { + "@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" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jasmine-core": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.1.1.tgz", + "integrity": "sha512-lmUfT5XcK9KKvt3lLYzn93hc4MGzlUBowExFVgzbSW0ZCrdeyS574dfsyfRhxbg81Wj4gk+RxUiTnj7KBfDA1g==", + "dev": true + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "json5": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", + "dev": true + }, + "jsonc-parser": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.1.0.tgz", + "integrity": "sha512-DRf0QjnNeCUds3xTjKlQQ3DpJD51GvDjJfnxUVWg6PZTo2otSm+slzNAxU/35hF8/oJIKoG9slq30JYOsF2azg==", + "dev": true + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true + }, + "karma": { + "version": "6.3.20", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.3.20.tgz", + "integrity": "sha512-HRNQhMuKOwKpjYlWiJP0DUrJOh+QjaI/DTaD8b9rEm4Il3tJ8MijutVZH4ts10LuUFst/CedwTS6vieCN8yTSw==", + "dev": true, + "requires": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.4.1", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dev": true, + "requires": { + "rimraf": "^3.0.0" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "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" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true + } + } + }, + "karma-chrome-launcher": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz", + "integrity": "sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ==", + "dev": true, + "requires": { + "which": "^1.2.1" + } + }, + "karma-coverage": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/karma-coverage/-/karma-coverage-2.2.0.tgz", + "integrity": "sha512-gPVdoZBNDZ08UCzdMHHhEImKrw1+PAOQOIiffv1YsvxFhBjqvo/SVXNk4tqn1SYqX0BJZT6S/59zgxiBe+9OuA==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.2.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.1", + "istanbul-reports": "^3.0.5", + "minimatch": "^3.0.4" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "karma-jasmine": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-5.0.1.tgz", + "integrity": "sha512-FkL1Kk+JAKmim8VWU8RXKZBpl0lLI7J8LijM0/q7oP7emfB6QMZV1Az+JgqGKSLpF0tYaav+KUVFQroZUxQTHA==", + "dev": true, + "requires": { + "jasmine-core": "^4.1.0" + } + }, + "karma-jasmine-html-reporter": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.7.0.tgz", + "integrity": "sha512-pzum1TL7j90DTE86eFt48/s12hqwQuiD+e5aXx2Dc9wDEn2LfGq6RoAxEZZjFiN0RDSCOnosEKRZWxbQ+iMpQQ==", + "dev": true, + "requires": {} + }, + "karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dev": true, + "requires": { + "source-map-support": "^0.5.5" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "klona": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", + "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", + "dev": true + }, + "less": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz", + "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==", + "dev": true, + "requires": { + "copy-anything": "^2.0.1", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "parse-node-version": "^1.0.1", + "source-map": "~0.6.0", + "tslib": "^2.3.0" + }, + "dependencies": { + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "optional": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "optional": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "optional": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true + } + } + }, + "less-loader": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.0.0.tgz", + "integrity": "sha512-9+LOWWjuoectIEx3zrfN83NAGxSUB5pWEabbbidVQVgZhN+wN68pOvuyirVlH1IK4VT1f3TmlyvAnCXh8O5KEw==", + "dev": true, + "requires": { + "klona": "^2.0.4" + } + }, + "license-webpack-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "dev": true, + "requires": { + "webpack-sources": "^3.0.0" + } + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "loader-runner": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz", + "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==", + "dev": true + }, + "loader-utils": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.0.tgz", + "integrity": "sha512-HVl9ZqccQihZ7JM85dco1MvO9G+ONvxoGa9rkhzFsneGLKSUg1gJf9bWzhRhcvm2qChhWpebQhP44qxjKIUCaQ==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "log4js": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.7.0.tgz", + "integrity": "sha512-KA0W9ffgNBLDj6fZCq/lRbgR6ABAodRIDHrZnS48vOtfKa4PzWImb0Md1lmGCdO3n3sbCm/n1/WmrNlZ8kCI3Q==", + "dev": true, + "requires": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.3" + } + }, + "lru-cache": { + "version": "7.14.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.0.tgz", + "integrity": "sha512-EIRtP1GrSJny0dqb50QXRUNBxHJhcpxHC++M5tD7RYbvLLn5KVWKsbyswSSqDuU15UFi3bgTQIY8nhDMeF6aDQ==", + "dev": true + }, + "magic-string": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.1.tgz", + "integrity": "sha512-ndThHmvgtieXe8J/VGPjG+Apu7v7ItcD5mhEIvOscWjPF/ccOiLxHaSuCAS2G+3x4GKsAbT8u7zdyamupui8Tg==", + "dev": true, + "requires": { + "sourcemap-codec": "^1.4.8" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, + "requires": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "dependencies": { + "@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "dev": true, + "requires": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "dev": true, + "requires": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + } + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true + }, + "memfs": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.7.tgz", + "integrity": "sha512-ygaiUSNalBX85388uskeCyhSAoOSgzBbtVCr9jA2RROssFL9Q19/ZXFqS+2Th2sr1ewNIWgFdLzLC3Yl1Zv+lw==", + "dev": true, + "requires": { + "fs-monkey": "^1.0.3" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "dev": true + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "mini-css-extract-plugin": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.6.1.tgz", + "integrity": "sha512-wd+SD57/K6DiV7jIR34P+s3uckTRuQvx0tKPcvjFlrEylk6P4mQ2KSWk1hblj1Kxaqok7LogKOieygXqBczNlg==", + "dev": true, + "requires": { + "schema-utils": "^4.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "minipass": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz", + "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "dev": true, + "requires": { + "encoding": "^0.1.12", + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "requires": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dev": true, + "requires": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + } + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "dev": true + }, + "needle": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.1.0.tgz", + "integrity": "sha512-gCE9weDhjVGCRqS8dwDR/D3GTAeyXLXuqp7I8EzH6DllZGXSUyxuqqLh+YX9rMAWaaTFyVAg6rHGL25dqvczKw==", + "dev": true, + "optional": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "dev": true, + "optional": true, + "requires": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "optional": true + }, + "node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "requires": { + "whatwg-url": "^5.0.0" + } + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "dev": true + }, + "node-gyp": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "dev": true, + "requires": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "node-gyp-build": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.5.0.tgz", + "integrity": "sha512-2iGbaQBV+ITgCz76ZEjmhUKAKVf7xfY1sRl4UiKQspfZMH2h06SyhNsnSVy50cwkFQDGLyif6m/6uFXHkOZ6rg==", + "dev": true, + "optional": true + }, + "node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==", + "dev": true + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-4.0.1.tgz", + "integrity": "sha512-EBk5QKKuocMJhB3BILuKhmaPjI8vNRSpIfO9woLC6NyHVkKKdVEdAO1mrT0ZfxNR1lKwCcTkuZfmGIFdizZ8Pg==", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true + }, + "npm-bundled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", + "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "dev": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-install-checks": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-5.0.0.tgz", + "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", + "dev": true, + "requires": { + "semver": "^7.1.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true + }, + "npm-package-arg": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.0.2.tgz", + "integrity": "sha512-v/miORuX8cndiOheW8p2moNuPJ7QhcFh9WGlTorruG8hXSA23vMTEp5hTCmDxic0nD8KHhj/NQgFuySD3GYY3g==", + "dev": true, + "requires": { + "hosted-git-info": "^5.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^4.0.0" + } + }, + "npm-packlist": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-5.1.3.tgz", + "integrity": "sha512-263/0NGrn32YFYi4J533qzrQ/krmmrWwhKkzwTuM4f/07ug51odoaNjUexxO4vxlzURHcmYMH1QjvHjsNDKLVg==", + "dev": true, + "requires": { + "glob": "^8.0.1", + "ignore-walk": "^5.0.1", + "npm-bundled": "^2.0.0", + "npm-normalize-package-bin": "^2.0.0" + }, + "dependencies": { + "npm-bundled": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-2.0.1.tgz", + "integrity": "sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw==", + "dev": true, + "requires": { + "npm-normalize-package-bin": "^2.0.0" + } + }, + "npm-normalize-package-bin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true + } + } + }, + "npm-pick-manifest": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-7.0.1.tgz", + "integrity": "sha512-IA8+tuv8KujbsbLQvselW2XQgmXWS47t3CB0ZrzsRZ82DbDfkcFunOaPm4X7qNuhMfq+FmV7hQT4iFVpHqV7mg==", + "dev": true, + "requires": { + "npm-install-checks": "^5.0.0", + "npm-normalize-package-bin": "^1.0.1", + "npm-package-arg": "^9.0.0", + "semver": "^7.3.5" + } + }, + "npm-registry-fetch": { + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-13.3.1.tgz", + "integrity": "sha512-eukJPi++DKRTjSBRcDZSDDsGqRK3ehbxfFUcgaRd0Yp6kRwOwh2WVn0r+8rMB4nnuzvAk6rQVzl6K5CkYOmnvw==", + "dev": true, + "requires": { + "make-fetch-happen": "^10.0.6", + "minipass": "^3.1.6", + "minipass-fetch": "^2.0.3", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^9.0.1", + "proc-log": "^2.0.0" + }, + "dependencies": { + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true + }, + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, + "make-fetch-happen": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", + "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dev": true, + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^16.1.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^3.1.6", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^2.0.3", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^9.0.0" + } + }, + "minipass-fetch": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", + "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^3.1.6", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + }, + "socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + } + } + } + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "requires": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + } + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true + }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.0.tgz", + "integrity": "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q==", + "dev": true, + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dev": true, + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "requires": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "dependencies": { + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true + } + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pacote": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-13.3.0.tgz", + "integrity": "sha512-auhJAUlfC2TALo6I0s1vFoPvVFgWGx+uz/PnIojTTgkGwlK3Np8sGJ0ghfFhiuzJXTZoTycMLk8uLskdntPbDw==", + "dev": true, + "requires": { + "@npmcli/git": "^3.0.0", + "@npmcli/installed-package-contents": "^1.0.7", + "@npmcli/promise-spawn": "^3.0.0", + "@npmcli/run-script": "^3.0.1", + "cacache": "^16.0.0", + "chownr": "^2.0.0", + "fs-minipass": "^2.1.0", + "infer-owner": "^1.0.4", + "minipass": "^3.1.6", + "mkdirp": "^1.0.4", + "npm-package-arg": "^9.0.0", + "npm-packlist": "^5.0.0", + "npm-pick-manifest": "^7.0.0", + "npm-registry-fetch": "^13.0.1", + "proc-log": "^2.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^5.0.0", + "read-package-json-fast": "^2.0.3", + "rimraf": "^3.0.2", + "ssri": "^9.0.0", + "tar": "^6.1.11" + } + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@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" + } + }, + "parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true + }, + "parse5-html-rewriting-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-6.0.1.tgz", + "integrity": "sha512-vwLQzynJVEfUlURxgnf51yAJDQTtVpNyGD8tKi2Za7m+akukNHxCcUQMAa/mUGLhCeicFdpy7Tlvj8ZNKadprg==", + "dev": true, + "requires": { + "parse5": "^6.0.1", + "parse5-sax-parser": "^6.0.1" + } + }, + "parse5-htmlparser2-tree-adapter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", + "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", + "dev": true, + "requires": { + "parse5": "^6.0.1" + } + }, + "parse5-sax-parser": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-6.0.1.tgz", + "integrity": "sha512-kXX+5S81lgESA0LsDuGjAlBybImAChYRMT+/uKCEXFBFOeEhS52qUCydGhU3qLRD8D9DVjaUo821WK7DM4iCeg==", + "dev": true, + "requires": { + "parse5": "^6.0.1" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true + }, + "piscina": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz", + "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==", + "dev": true, + "requires": { + "eventemitter-asyncresource": "^1.0.0", + "hdr-histogram-js": "^2.0.1", + "hdr-histogram-percentiles-obj": "^3.0.0", + "nice-napi": "^1.0.2" + } + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "postcss": { + "version": "8.4.16", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.16.tgz", + "integrity": "sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==", + "dev": true, + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "postcss-attribute-case-insensitive": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz", + "integrity": "sha512-XIidXV8fDr0kKt28vqki84fRK8VW8eTuIa4PChv2MqKuT6C9UjmSKzen6KaWhWEoYvwxFCa7n/tC1SZ3tyq4SQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-clamp": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-clamp/-/postcss-clamp-4.1.0.tgz", + "integrity": "sha512-ry4b1Llo/9zz+PKC+030KUnPITTJAHeOwjfAyyB60eT0AorGLdzp52s31OsPRHRf8NchkgFoG2y6fCfn1IV1Ow==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-functional-notation": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/postcss-color-functional-notation/-/postcss-color-functional-notation-4.2.4.tgz", + "integrity": "sha512-2yrTAUZUab9s6CpxkxC4rVgFEVaR6/2Pipvi6qcgvnYiVqZcbDHEoBDhrXzyb7Efh2CCfHQNtcqWcIruDTIUeg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-hex-alpha": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/postcss-color-hex-alpha/-/postcss-color-hex-alpha-8.0.4.tgz", + "integrity": "sha512-nLo2DCRC9eE4w2JmuKgVA3fGL3d01kGq752pVALF68qpGLmx2Qrk91QTKkdUqqp45T1K1XV8IhQpcu1hoAQflQ==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-color-rebeccapurple": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/postcss-color-rebeccapurple/-/postcss-color-rebeccapurple-7.1.1.tgz", + "integrity": "sha512-pGxkuVEInwLHgkNxUc4sdg4g3py7zUeCQ9sMfwyHAT+Ezk8a4OaaVZ8lIY5+oNqA/BXXgLyXv0+5wHP68R79hg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-custom-media": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-custom-media/-/postcss-custom-media-8.0.2.tgz", + "integrity": "sha512-7yi25vDAoHAkbhAzX9dHx2yc6ntS4jQvejrNcC+csQJAXjj15e7VcWfMgLqBNAbOvqi5uIa9huOVwdHbf+sKqg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-custom-properties": { + "version": "12.1.9", + "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-12.1.9.tgz", + "integrity": "sha512-/E7PRvK8DAVljBbeWrcEQJPG72jaImxF3vvCNFwv9cC8CzigVoNIpeyfnJzphnN3Fd8/auBf5wvkw6W9MfmTyg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-custom-selectors": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-custom-selectors/-/postcss-custom-selectors-6.0.3.tgz", + "integrity": "sha512-fgVkmyiWDwmD3JbpCmB45SvvlCD6z9CG6Ie6Iere22W5aHea6oWa7EM2bpnv2Fj3I94L3VbtvX9KqwSi5aFzSg==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-dir-pseudo-class": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/postcss-dir-pseudo-class/-/postcss-dir-pseudo-class-6.0.5.tgz", + "integrity": "sha512-eqn4m70P031PF7ZQIvSgy9RSJ5uI2171O/OO/zcRNYpJbvaeKFUlar1aJ7rmgiQtbm0FSPsRewjpdS0Oew7MPA==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-double-position-gradients": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/postcss-double-position-gradients/-/postcss-double-position-gradients-3.1.2.tgz", + "integrity": "sha512-GX+FuE/uBR6eskOK+4vkXgT6pDkexLokPaz/AbJna9s5Kzp/yl488pKPjhy0obB475ovfT1Wv8ho7U/cHNaRgQ==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-env-function": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/postcss-env-function/-/postcss-env-function-4.0.6.tgz", + "integrity": "sha512-kpA6FsLra+NqcFnL81TnsU+Z7orGtDTxcOhl6pwXeEq1yFPpRMkCDpHhrz8CFQDr/Wfm0jLiNQ1OsGGPjlqPwA==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-focus-visible": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-visible/-/postcss-focus-visible-6.0.4.tgz", + "integrity": "sha512-QcKuUU/dgNsstIK6HELFRT5Y3lbrMLEOwG+A4s5cA+fx3A3y/JTq3X9LaOj3OC3ALH0XqyrgQIgey/MIZ8Wczw==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "postcss-focus-within": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-focus-within/-/postcss-focus-within-5.0.4.tgz", + "integrity": "sha512-vvjDN++C0mu8jz4af5d52CB184ogg/sSxAFS+oUJQq2SuCe7T5U2iIsVJtsCp2d6R4j0jr5+q3rPkBVZkXD9fQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.9" + } + }, + "postcss-font-variant": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-font-variant/-/postcss-font-variant-5.0.0.tgz", + "integrity": "sha512-1fmkBaCALD72CK2a9i468mA/+tr9/1cBxRRMXOUaZqO43oWPR5imcyPjXwuv7PXbCid4ndlP5zWhidQVVa3hmA==", + "dev": true, + "requires": {} + }, + "postcss-gap-properties": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/postcss-gap-properties/-/postcss-gap-properties-3.0.5.tgz", + "integrity": "sha512-IuE6gKSdoUNcvkGIqdtjtcMtZIFyXZhmFd5RUlg97iVEvp1BZKV5ngsAjCjrVy+14uhGBQl9tzmi1Qwq4kqVOg==", + "dev": true, + "requires": {} + }, + "postcss-image-set-function": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/postcss-image-set-function/-/postcss-image-set-function-4.0.7.tgz", + "integrity": "sha512-9T2r9rsvYzm5ndsBE8WgtrMlIT7VbtTfE7b3BQnudUqnBcBo7L758oc+o+pdj/dUV0l5wjwSdjeOH2DZtfv8qw==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-import": { + "version": "15.0.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.0.0.tgz", + "integrity": "sha512-Y20shPQ07RitgBGv2zvkEAu9bqvrD77C9axhj/aA1BQj4czape2MdClCExvB27EwYEJdGgKZBpKanb0t1rK2Kg==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + } + }, + "postcss-initial": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-initial/-/postcss-initial-4.0.1.tgz", + "integrity": "sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==", + "dev": true, + "requires": {} + }, + "postcss-lab-function": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/postcss-lab-function/-/postcss-lab-function-4.2.1.tgz", + "integrity": "sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==", + "dev": true, + "requires": { + "@csstools/postcss-progressive-custom-properties": "^1.1.0", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-loader": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.1.tgz", + "integrity": "sha512-VRviFEyYlLjctSM93gAZtcJJ/iSkPZ79zWbN/1fSH+NisBByEiVLqpdVDrPLVSi8DX0oJo12kL/GppTBdKVXiQ==", + "dev": true, + "requires": { + "cosmiconfig": "^7.0.0", + "klona": "^2.0.5", + "semver": "^7.3.7" + } + }, + "postcss-logical": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/postcss-logical/-/postcss-logical-5.0.4.tgz", + "integrity": "sha512-RHXxplCeLh9VjinvMrZONq7im4wjWGlRJAqmAVLXyZaXwfDWP73/oq4NdIp+OZwhQUMj0zjqDfM5Fj7qby+B4g==", + "dev": true, + "requires": {} + }, + "postcss-media-minmax": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/postcss-media-minmax/-/postcss-media-minmax-5.0.0.tgz", + "integrity": "sha512-yDUvFf9QdFZTuCUg0g0uNSHVlJ5X1lSzDZjPSFaiCWvjgsvu8vEVxtahPrLMinIDEEGnx6cBe6iqdx5YWz08wQ==", + "dev": true, + "requires": {} + }, + "postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "requires": {} + }, + "postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dev": true, + "requires": { + "icss-utils": "^5.0.0" + } + }, + "postcss-nesting": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/postcss-nesting/-/postcss-nesting-10.2.0.tgz", + "integrity": "sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==", + "dev": true, + "requires": { + "@csstools/selector-specificity": "^2.0.0", + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-opacity-percentage": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/postcss-opacity-percentage/-/postcss-opacity-percentage-1.1.2.tgz", + "integrity": "sha512-lyUfF7miG+yewZ8EAk9XUBIlrHyUE6fijnesuz+Mj5zrIHIEw6KcIZSOk/elVMqzLvREmXB83Zi/5QpNRYd47w==", + "dev": true + }, + "postcss-overflow-shorthand": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-overflow-shorthand/-/postcss-overflow-shorthand-3.0.4.tgz", + "integrity": "sha512-otYl/ylHK8Y9bcBnPLo3foYFLL6a6Ak+3EQBPOTR7luMYCOsiVTUk1iLvNf6tVPNGXcoL9Hoz37kpfriRIFb4A==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-page-break": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postcss-page-break/-/postcss-page-break-3.0.4.tgz", + "integrity": "sha512-1JGu8oCjVXLa9q9rFTo4MbeeA5FMe00/9C7lN4va606Rdb+HkxXtXsmEDrIraQ11fGz/WvKWa8gMuCKkrXpTsQ==", + "dev": true, + "requires": {} + }, + "postcss-place": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/postcss-place/-/postcss-place-7.0.5.tgz", + "integrity": "sha512-wR8igaZROA6Z4pv0d+bvVrvGY4GVHihBCBQieXFY3kuSuMyOmEnnfFzHl/tQuqHZkfkIVBEbDvYcFfHmpSet9g==", + "dev": true, + "requires": { + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-preset-env": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/postcss-preset-env/-/postcss-preset-env-7.8.0.tgz", + "integrity": "sha512-leqiqLOellpLKfbHkD06E04P6d9ZQ24mat6hu4NSqun7WG0UhspHR5Myiv/510qouCjoo4+YJtNOqg5xHaFnCA==", + "dev": true, + "requires": { + "@csstools/postcss-cascade-layers": "^1.0.5", + "@csstools/postcss-color-function": "^1.1.1", + "@csstools/postcss-font-format-keywords": "^1.0.1", + "@csstools/postcss-hwb-function": "^1.0.2", + "@csstools/postcss-ic-unit": "^1.0.1", + "@csstools/postcss-is-pseudo-class": "^2.0.7", + "@csstools/postcss-nested-calc": "^1.0.0", + "@csstools/postcss-normalize-display-values": "^1.0.1", + "@csstools/postcss-oklab-function": "^1.1.1", + "@csstools/postcss-progressive-custom-properties": "^1.3.0", + "@csstools/postcss-stepped-value-functions": "^1.0.1", + "@csstools/postcss-text-decoration-shorthand": "^1.0.0", + "@csstools/postcss-trigonometric-functions": "^1.0.2", + "@csstools/postcss-unset-value": "^1.0.2", + "autoprefixer": "^10.4.8", + "browserslist": "^4.21.3", + "css-blank-pseudo": "^3.0.3", + "css-has-pseudo": "^3.0.4", + "css-prefers-color-scheme": "^6.0.3", + "cssdb": "^7.0.0", + "postcss-attribute-case-insensitive": "^5.0.2", + "postcss-clamp": "^4.1.0", + "postcss-color-functional-notation": "^4.2.4", + "postcss-color-hex-alpha": "^8.0.4", + "postcss-color-rebeccapurple": "^7.1.1", + "postcss-custom-media": "^8.0.2", + "postcss-custom-properties": "^12.1.8", + "postcss-custom-selectors": "^6.0.3", + "postcss-dir-pseudo-class": "^6.0.5", + "postcss-double-position-gradients": "^3.1.2", + "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.5", + "postcss-image-set-function": "^4.0.7", + "postcss-initial": "^4.0.1", + "postcss-lab-function": "^4.2.1", + "postcss-logical": "^5.0.4", + "postcss-media-minmax": "^5.0.0", + "postcss-nesting": "^10.1.10", + "postcss-opacity-percentage": "^1.1.2", + "postcss-overflow-shorthand": "^3.0.4", + "postcss-page-break": "^3.0.4", + "postcss-place": "^7.0.5", + "postcss-pseudo-class-any-link": "^7.1.6", + "postcss-replace-overflow-wrap": "^4.0.0", + "postcss-selector-not": "^6.0.1", + "postcss-value-parser": "^4.2.0" + } + }, + "postcss-pseudo-class-any-link": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/postcss-pseudo-class-any-link/-/postcss-pseudo-class-any-link-7.1.6.tgz", + "integrity": "sha512-9sCtZkO6f/5ML9WcTLcIyV1yz9D1rf0tWc+ulKcvV30s0iZKS/ONyETvoWsr6vnrmW+X+KmuK3gV/w5EWnT37w==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-replace-overflow-wrap": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-replace-overflow-wrap/-/postcss-replace-overflow-wrap-4.0.0.tgz", + "integrity": "sha512-KmF7SBPphT4gPPcKZc7aDkweHiKEEO8cla/GjcBK+ckKxiZslIu3C4GCRW3DNfL0o7yW7kMQu9xlZ1kXRXLXtw==", + "dev": true, + "requires": {} + }, + "postcss-selector-not": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-selector-not/-/postcss-selector-not-6.0.1.tgz", + "integrity": "sha512-1i9affjAe9xu/y9uqWH+tD4r6/hDaXJruk8xn2x1vzxC2U3J3LKO3zJW4CyxlNhA56pADJ/djpEwpH1RClI2rQ==", + "dev": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true + }, + "primeicons": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/primeicons/-/primeicons-6.0.1.tgz", + "integrity": "sha512-KDeO94CbWI4pKsPnYpA1FPjo79EsY9I+M8ywoPBSf9XMXoe/0crjbUK7jcQEDHuc0ZMRIZsxH3TYLv4TUtHmAA==" + }, + "primeng": { + "version": "14.1.2", + "resolved": "https://registry.npmjs.org/primeng/-/primeng-14.1.2.tgz", + "integrity": "sha512-iLMeORiLD46SNAotxCwRXoaRMXLs3ZbFzyePrPSNAFQbKEbsLfpUvsAUAatb/TA0jd8TnXgdCjZ07ee4664XVQ==", + "requires": { + "tslib": "^2.3.0" + } + }, + "proc-log": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", + "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "dependencies": { + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + } + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "dev": true, + "optional": true + }, + "psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "dev": true, + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "requires": { + "pify": "^2.3.0" + } + }, + "read-package-json": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-5.0.2.tgz", + "integrity": "sha512-BSzugrt4kQ/Z0krro8zhTwV1Kd79ue25IhNN/VtHFy1mG/6Tluyi+msc0UpwaoQzxSHa28mntAjIZY6kEgfR9Q==", + "dev": true, + "requires": { + "glob": "^8.0.1", + "json-parse-even-better-errors": "^2.3.1", + "normalize-package-data": "^4.0.0", + "npm-normalize-package-bin": "^2.0.0" + }, + "dependencies": { + "npm-normalize-package-bin": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", + "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true + } + } + }, + "read-package-json-fast": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", + "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", + "dev": true, + "requires": { + "json-parse-even-better-errors": "^2.3.0", + "npm-normalize-package-bin": "^1.0.1" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz", + "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==", + "dev": true, + "requires": { + "regenerate": "^1.4.2" + } + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", + "dev": true + }, + "regenerator-transform": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", + "dev": true + }, + "regexpu-core": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.2.1.tgz", + "integrity": "sha512-HrnlNtpvqP1Xkb28tMhBUO2EbyUHdQlsnlAhzWcwHy8WJR53UWr7/MAvqrsQKMbV4qdpv03oTMG8iIhfsPFktQ==", + "dev": true, + "requires": { + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsgen": "^0.7.1", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.0.0" + } + }, + "regjsgen": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.7.1.tgz", + "integrity": "sha512-RAt+8H2ZEzHeYWxZ3H2z6tF18zyyOnlcdaafLrm21Bguj7uZy6ULibiAFdXEtKQY4Sy7wDTwDiOazasMLc4KPA==", + "dev": true + }, + "regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true + } + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", + "dev": true, + "requires": { + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "dev": true, + "requires": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dev": true, + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "dev": true + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rxjs": { + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.7.tgz", + "integrity": "sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==", + "requires": { + "tslib": "^2.1.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "devOptional": true + }, + "sass": { + "version": "1.54.4", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.54.4.tgz", + "integrity": "sha512-3tmF16yvnBwtlPrNBHw/H907j8MlOX8aTBnlNX1yrKx24RKcJGPyLhFUwkoKBKesR3unP93/2z14Ll8NicwQUA==", + "dev": true, + "requires": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + } + }, + "sass-loader": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.0.2.tgz", + "integrity": "sha512-BbiqbVmbfJaWVeOOAu2o7DhYWtcNmTfvroVgFXa6k2hHheMxNAeDHLNoDy/Q5aoaVlz0LH+MbMktKwm9vN/j8Q==", + "dev": true, + "requires": { + "klona": "^2.0.4", + "neo-async": "^2.6.2" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "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-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + } + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "selfsigned": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz", + "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==", + "dev": true, + "requires": { + "node-forge": "^1" + } + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } + } + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dev": true, + "requires": { + "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" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true + }, + "socket.io": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.2.tgz", + "integrity": "sha512-6fCnk4ARMPZN448+SQcnn1u8OHUC72puJcNtSgg2xS34Cu7br1gQ09YKkO1PFfDn/wyUE9ZgMAwosJed003+NQ==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.2", + "engine.io": "~6.2.0", + "socket.io-adapter": "~2.4.0", + "socket.io-parser": "~4.2.0" + } + }, + "socket.io-adapter": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.4.0.tgz", + "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==", + "dev": true + }, + "socket.io-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", + "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", + "dev": true, + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + } + }, + "sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dev": true, + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", + "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + } + }, + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "dev": true + }, + "source-map-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.0.tgz", + "integrity": "sha512-i3KVgM3+QPAHNbGavK+VBq03YoJl24m9JWNbLgsjTj8aJzXG9M61bantBTNBt7CNwY2FYf+RJRYJ3pzalKjIrw==", + "dev": true, + "requires": { + "abab": "^2.0.6", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", + "dev": true + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", + "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", + "dev": true + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "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" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "ssri": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", + "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "dev": true + }, + "streamroller": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.3.tgz", + "integrity": "sha512-CphIJyFx2SALGHeINanjFRKQ4l7x2c+rXYJ4BMq0gd+ZK0gi4VT8b+eHe2wi58x4UayBAKx4xtHpXT/ea1cz8w==", + "dev": true, + "requires": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true + } + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "stylus": { + "version": "0.59.0", + "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.59.0.tgz", + "integrity": "sha512-lQ9w/XIOH5ZHVNuNbWW8D822r+/wBSO/d6XvtyHLF7LW4KaCIDeVbvn5DF8fGCJAUCwVhVi/h6J0NUcnylUEjg==", + "dev": true, + "requires": { + "@adobe/css-tools": "^4.0.1", + "debug": "^4.3.2", + "glob": "^7.1.6", + "sax": "~1.2.4", + "source-map": "^0.7.3" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "stylus-loader": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-7.0.0.tgz", + "integrity": "sha512-WTbtLrNfOfLgzTaR9Lj/BPhQroKk/LC1hfTXSUbrxmxgfUo3Y3LpmKRVA2R1XbjvTAvOfaian9vOyfv1z99E+A==", + "dev": true, + "requires": { + "fast-glob": "^3.2.11", + "klona": "^2.0.5", + "normalize-path": "^3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "dev": true + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true + }, + "tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "dev": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + } + }, + "terser": { + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", + "dev": true, + "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + } + }, + "terser-webpack-plugin": { + "version": "5.3.6", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz", + "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.14", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "terser": "^5.14.1" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "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-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true + }, + "tough-cookie": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", + "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "dependencies": { + "universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==" + } + } + }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, + "ts-node": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.3.0.tgz", + "integrity": "sha512-dyNS/RqyVTDcmNM4NIBAeDMpsAdaQ+ojdf0GOLqE6nwJOgzEkdRNzJywhDfwnuvB10oa6NLVG1rUJQCpRN7qoQ==", + "dev": true, + "requires": { + "arg": "^4.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "source-map-support": "^0.5.6", + "yn": "^3.0.0" + } + }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==", + "dev": true + }, + "typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true + }, + "ua-parser-js": { + "version": "0.7.31", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", + "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", + "dev": true + }, + "unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", + "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true + }, + "update-browserslist-db": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "dev": true + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", + "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true + }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", + "dev": true + }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dev": true, + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "webpack": { + "version": "5.74.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.74.0.tgz", + "integrity": "sha512-A2InDwnhhGN4LYctJj6M1JEaGL7Luj6LOmyBHjcI8529cm5p6VXiTIW2sn6ffvEAKmveLzvu4jrihwXtPojlAA==", + "dev": true, + "requires": { + "@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.7.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.10.0", + "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-even-better-errors": "^2.3.1", + "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.4.0", + "webpack-sources": "^3.2.3" + }, + "dependencies": { + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "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-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "requires": {} + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dev": true, + "requires": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + } + } + }, + "webpack-dev-server": { + "version": "4.11.0", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.0.tgz", + "integrity": "sha512-L5S4Q2zT57SK7tazgzjMiSMBdsw+rGYIX27MgPgx7LDhWO0lViPrHKoLS7jo5In06PWYAhlYu3PbyoC6yAThbw==", + "dev": true, + "requires": { + "@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/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.1", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.0.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.4.2" + }, + "dependencies": { + "schema-utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz", + "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.8.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.0.0" + } + }, + "ws": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.9.0.tgz", + "integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==", + "dev": true, + "requires": {} + } + } + }, + "webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true + }, + "webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "dev": true, + "requires": { + "typed-assert": "^1.0.8" + } + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", + "dev": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "dev": true, + "requires": {} + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true + }, + "yargs": { + "version": "17.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.4.1.tgz", + "integrity": "sha512-WSZD9jgobAg3ZKuCQZSa3g9QOJeCCqLoLAykiWgmXnDo9EPnn4RPf5qVTtzgOx66o6/oqhcA5tHtJXpG8pMt3g==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, + "zone.js": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.11.8.tgz", + "integrity": "sha512-82bctBg2hKcEJ21humWIkXRlLBBmrc3nN7DFh5LGGhcyycO2S7FN8NmdvlcKaGFDNVL4/9kFLmwmInTavdJERA==", + "requires": { + "tslib": "^2.3.0" + } + } + } +} diff --git a/kdb-web/package.json b/kdb-web/package.json new file mode 100644 index 0000000000..5d0195d078 --- /dev/null +++ b/kdb-web/package.json @@ -0,0 +1,49 @@ +{ + "name": "kdb-web", + "version": "0.3.0", + "scripts": { + "ng": "ng", + "update-version": "ts-node -O '{\"module\": \"commonjs\"}' update-version.ts", + "prestart": "npm run update-version", + "start": "ng serve", + "prebuild": "npm run update-version", + "build": "ng build", + "watch": "ng build --watch --configuration development", + "test": "ng test" + }, + "private": true, + "dependencies": { + "@angular/animations": "^14.0.0", + "@angular/common": "^14.0.0", + "@angular/compiler": "^14.0.0", + "@angular/core": "^14.0.0", + "@angular/forms": "^14.0.0", + "@angular/platform-browser": "^14.0.0", + "@angular/platform-browser-dynamic": "^14.0.0", + "@angular/router": "^14.0.0", + "@auth0/angular-jwt": "^5.1.0", + "@microsoft/signalr": "^6.0.9", + "@ngx-translate/core": "^14.0.0", + "@ngx-translate/http-loader": "^7.0.0", + "primeicons": "^6.0.1", + "primeng": "^14.1.2", + "rxjs": "~7.5.0", + "tslib": "^2.3.0", + "zone.js": "~0.11.4" + }, + "devDependencies": { + "@angular-devkit/build-angular": "^14.0.0", + "@angular/cli": "~14.0.0", + "@angular/compiler-cli": "^14.0.0", + "@types/jasmine": "~4.0.0", + "@types/node": "^18.8.3", + "jasmine-core": "~4.1.0", + "karma": "~6.3.0", + "karma-chrome-launcher": "~3.1.0", + "karma-coverage": "~2.2.0", + "karma-jasmine": "~5.0.0", + "karma-jasmine-html-reporter": "~1.7.0", + "ts-node": "~8.3.0", + "typescript": "~4.7.2" + } +} diff --git a/kdb-web/src/app/app-routing.module.ts b/kdb-web/src/app/app-routing.module.ts new file mode 100644 index 0000000000..803deb705b --- /dev/null +++ b/kdb-web/src/app/app-routing.module.ts @@ -0,0 +1,22 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { NotFoundComponent } from './components/error/not-found/not-found.component'; +import { AuthRoles } from './models/auth/auth-roles.enum'; +import { AuthGuard } from './modules/shared/guards/auth/auth.guard'; + +const routes: Routes = [ + { path: '', redirectTo: 'dashboard', pathMatch: 'full' }, + { path: 'dashboard', loadChildren: () => import('./modules/view/dashboard/dashboard.module').then(m => m.DashboardModule), canActivate: [AuthGuard] }, + { path: 'change-password', loadChildren: () => import('./modules/view/change-password/change-password.module').then(m => m.ChangePasswordModule), canActivate: [AuthGuard] }, + { path: 'user-settings', loadChildren: () => import('./modules/view/user-settings/user-settings.module').then(m => m.UserSettingsModule), canActivate: [AuthGuard] }, + { path: 'auth', loadChildren: () => import('./modules/auth/auth.module').then(m => m.AuthModule) }, + { path: 'admin/settings', loadChildren: () => import('./modules/admin/settings/settings.module').then(m => m.SettingsModule), canActivate: [AuthGuard], data: { role: AuthRoles.Admin } }, + { path: 'admin/users', loadChildren: () => import('./modules/admin/auth-users/auth-user.module').then(m => m.AuthUserModule), canActivate: [AuthGuard], data: { role: AuthRoles.Admin } }, + { path: '404', component: NotFoundComponent} +]; + +@NgModule({ + imports: [RouterModule.forRoot(routes)], + exports: [RouterModule] +}) +export class AppRoutingModule { } diff --git a/kdb-web/src/app/app.component.html b/kdb-web/src/app/app.component.html new file mode 100644 index 0000000000..a9daaf7237 --- /dev/null +++ b/kdb-web/src/app/app.component.html @@ -0,0 +1,36 @@ +
+ + + +
+
+ +
+
+
+ +
+
+
+ + +
+ + + + + + + + + +
+ + +
+
+
+ +
\ No newline at end of file diff --git a/kdb-web/src/app/app.component.scss b/kdb-web/src/app/app.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-web/src/app/app.component.spec.ts b/kdb-web/src/app/app.component.spec.ts new file mode 100644 index 0000000000..3d9b4502d6 --- /dev/null +++ b/kdb-web/src/app/app.component.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; +import { RouterTestingModule } from '@angular/router/testing'; +import { AppComponent } from './app.component'; + +describe('AppComponent', () => { + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ + RouterTestingModule + ], + declarations: [ + AppComponent + ], + }).compileComponents(); + }); +}); diff --git a/kdb-web/src/app/app.component.ts b/kdb-web/src/app/app.component.ts new file mode 100644 index 0000000000..90758e7d54 --- /dev/null +++ b/kdb-web/src/app/app.component.ts @@ -0,0 +1,21 @@ +import { Component, OnInit } from '@angular/core'; +import { AuthService } from './services/auth/auth.service'; +import { ThemeService } from './services/theme/theme.service'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'] +}) +export class AppComponent implements OnInit { + + constructor( + public authService: AuthService, + public themeService: ThemeService, + ) { } + + ngOnInit(): void { + this.themeService.loadTheme(); + this.themeService.loadMenu(); + } +} diff --git a/kdb-web/src/app/app.module.ts b/kdb-web/src/app/app.module.ts new file mode 100644 index 0000000000..c8ae9aed0a --- /dev/null +++ b/kdb-web/src/app/app.module.ts @@ -0,0 +1,81 @@ +import { HttpClient } from '@angular/common/http'; +import { APP_INITIALIZER, ErrorHandler, NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { JwtModule } from '@auth0/angular-jwt'; +import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; +import { TranslateHttpLoader } from '@ngx-translate/http-loader'; +import { ConfirmationService, MessageService } from 'primeng/api'; +import { DialogService } from 'primeng/dynamicdialog'; +import { AppRoutingModule } from './app-routing.module'; +import { AppComponent } from './app.component'; +import { FooterComponent } from './components/footer/footer.component'; +import { HeaderComponent } from './components/header/header.component'; +import { SidebarComponent } from './components/sidebar/sidebar.component'; +import { SpinnerComponent } from './components/spinner/spinner.component'; +import { SharedModule } from './modules/shared/shared.module'; +import { ErrorHandlerService } from './services/error-handler/error-handler.service'; +import { SettingsService } from './services/settings/settings.service'; +import { NotFoundComponent } from './components/error/not-found/not-found.component'; + +@NgModule({ + declarations: [ + AppComponent, + HeaderComponent, + SidebarComponent, + FooterComponent, + SpinnerComponent, + NotFoundComponent, + ], + imports: [ + BrowserModule, + BrowserAnimationsModule, + AppRoutingModule, + SharedModule, + JwtModule.forRoot({ + config: { + tokenGetter, + allowedDomains: ['localhost:5000', 'localhost:5001'], + disallowedRoutes: [] + } + }), + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useFactory: HttpLoaderFactory, + deps: [HttpClient] + } + }) + ], + providers: [ + { + provide: APP_INITIALIZER, + useFactory: configurationFactory, + deps: [SettingsService], + multi: true + }, + { + provide: ErrorHandler, + useClass: ErrorHandlerService + }, + MessageService, + ConfirmationService, + DialogService + ], + bootstrap: [AppComponent] +}) +export class AppModule { } + +export function configurationFactory(settingsService: SettingsService): () => Promise { + return (): Promise => { + return settingsService.loadSettings(); + }; +} + +export function tokenGetter(): string { + return localStorage.getItem('jwt') ?? ''; +} + +export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader { + return new TranslateHttpLoader(http); +} diff --git a/kdb-web/src/app/components/error/not-found/not-found.component.html b/kdb-web/src/app/components/error/not-found/not-found.component.html new file mode 100644 index 0000000000..86079dc270 --- /dev/null +++ b/kdb-web/src/app/components/error/not-found/not-found.component.html @@ -0,0 +1,15 @@ +
+
+
+
+
+
+

+ {{'common.error' | translate}} +

+
+ +
+ {{'common.404' | translate}} +
+
\ No newline at end of file diff --git a/kdb-web/src/app/components/error/not-found/not-found.component.scss b/kdb-web/src/app/components/error/not-found/not-found.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-web/src/app/components/error/not-found/not-found.component.spec.ts b/kdb-web/src/app/components/error/not-found/not-found.component.spec.ts new file mode 100644 index 0000000000..9d41c99a66 --- /dev/null +++ b/kdb-web/src/app/components/error/not-found/not-found.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { NotFoundComponent } from './not-found.component'; + +describe('NotFoundComponent', () => { + let component: NotFoundComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ NotFoundComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(NotFoundComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/components/error/not-found/not-found.component.ts b/kdb-web/src/app/components/error/not-found/not-found.component.ts new file mode 100644 index 0000000000..9b4c5f594d --- /dev/null +++ b/kdb-web/src/app/components/error/not-found/not-found.component.ts @@ -0,0 +1,18 @@ +import { Location } from '@angular/common'; +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-not-found', + templateUrl: './not-found.component.html', + styleUrls: ['./not-found.component.scss'] +}) +export class NotFoundComponent implements OnInit { + + constructor( + public location: Location + ) { } + + ngOnInit(): void { + } + +} diff --git a/kdb-web/src/app/components/footer/footer.component.html b/kdb-web/src/app/components/footer/footer.component.html new file mode 100644 index 0000000000..240f858334 --- /dev/null +++ b/kdb-web/src/app/components/footer/footer.component.html @@ -0,0 +1,26 @@ +
+
+
+ + {{'footer.frontend' | translate}}: + + + {{frontendVersion.getVersionString()}} + +
+ + | + +
+ + {{'footer.backend' | translate}}: + + + {{backendVersion.getVersionString()}} + +
+
+ +
\ No newline at end of file diff --git a/kdb-web/src/app/components/footer/footer.component.scss b/kdb-web/src/app/components/footer/footer.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-web/src/app/components/footer/footer.component.spec.ts b/kdb-web/src/app/components/footer/footer.component.spec.ts new file mode 100644 index 0000000000..a3c4af95bf --- /dev/null +++ b/kdb-web/src/app/components/footer/footer.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FooterComponent } from './footer.component'; + +describe('FooterComponent', () => { + let component: FooterComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ FooterComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(FooterComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/components/footer/footer.component.ts b/kdb-web/src/app/components/footer/footer.component.ts new file mode 100644 index 0000000000..bb2fa2eb02 --- /dev/null +++ b/kdb-web/src/app/components/footer/footer.component.ts @@ -0,0 +1,46 @@ +import { Component, OnInit } from '@angular/core'; +import { type } from 'os'; +import { catchError } from 'rxjs/operators'; +import { SoftwareVersion } from 'src/app/models/config/software-version'; +import { GuiService } from 'src/app/services/gui/gui.service'; +import { SettingsService } from 'src/app/services/settings/settings.service'; +import { SpinnerService } from 'src/app/services/spinner/spinner.service'; + +@Component({ + selector: 'app-footer', + templateUrl: './footer.component.html', + styleUrls: ['./footer.component.scss'] +}) +export class FooterComponent implements OnInit { + + + frontendVersion!: SoftwareVersion; + backendVersion!: SoftwareVersion; + + constructor( + private settings: SettingsService, + private guiService: GuiService, + private spinnerService: SpinnerService + ) { } + + ngOnInit(): void { + this.frontendVersion = this.settings.getWebVersion() ?? new SoftwareVersion('0', '0', '0'); + + this.spinnerService.showSpinner(); + this.guiService.getApiVersion() + .pipe(catchError(err => { + this.spinnerService.hideSpinner(); + throw err; + })) + .subscribe(version => { + this.spinnerService.hideSpinner(); + const webVersion = new SoftwareVersion( + version.major, + version.minor, + version.micro + ); + this.backendVersion = webVersion; + }); + } + +} diff --git a/kdb-web/src/app/components/header/header.component.html b/kdb-web/src/app/components/header/header.component.html new file mode 100644 index 0000000000..d48d039c87 --- /dev/null +++ b/kdb-web/src/app/components/header/header.component.html @@ -0,0 +1,25 @@ +
+
+ +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+
\ No newline at end of file diff --git a/kdb-web/src/app/components/header/header.component.scss b/kdb-web/src/app/components/header/header.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-web/src/app/components/header/header.component.spec.ts b/kdb-web/src/app/components/header/header.component.spec.ts new file mode 100644 index 0000000000..381e8e80c5 --- /dev/null +++ b/kdb-web/src/app/components/header/header.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { HeaderComponent } from './header.component'; + +describe('HeaderComponent', () => { + let component: HeaderComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ HeaderComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(HeaderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/components/header/header.component.ts b/kdb-web/src/app/components/header/header.component.ts new file mode 100644 index 0000000000..6d4ad0eeeb --- /dev/null +++ b/kdb-web/src/app/components/header/header.component.ts @@ -0,0 +1,168 @@ +import { Component, EventEmitter, OnInit, Output } from '@angular/core'; +import { Router } from '@angular/router'; +import { LangChangeEvent, TranslateService } from '@ngx-translate/core'; +import { MenuItem, PrimeNGConfig } from 'primeng/api'; +import { catchError } from 'rxjs/operators'; +import { AuthService } from 'src/app/services/auth/auth.service'; +import { SettingsService } from 'src/app/services/settings/settings.service'; +import { SpinnerService } from 'src/app/services/spinner/spinner.service'; +import { ThemeService } from 'src/app/services/theme/theme.service'; + +@Component({ + selector: 'app-header', + templateUrl: './header.component.html', + styleUrls: ['./header.component.scss'] +}) +export class HeaderComponent implements OnInit { + @Output() isSidebarFullWidth: EventEmitter = new EventEmitter(this.themeService.isSidebarOpen); + + langList: MenuItem[] = []; + themeList: MenuItem[] = []; + userMenuList!: MenuItem[]; + + constructor( + private authService: AuthService, + private router: Router, + private themeService: ThemeService, + private spinnerService: SpinnerService, + private settings: SettingsService, + private translateService: TranslateService, + private config: PrimeNGConfig + ) { } + + ngOnInit(): void { + this.translateService.setDefaultLang('en'); + this.initMenuLists(); + this.loadLang(); + this.translateService.onLangChange.subscribe((event: LangChangeEvent) => { + this.initUserMenuList(); + }); + } + + initUserMenuList(): void { + this.spinnerService.showSpinner(); + const mail = this.authService.getEMailFromDecodedToken(this.authService.getDecodedToken()); + this.authService.getUserByEMail(mail ?? '') + .pipe(catchError(err => { + this.spinnerService.hideSpinner(); + this.authService.logout(); + throw err; + })) + .subscribe(user => { + this.spinnerService.hideSpinner(); + + + this.userMenuList = [ + { + label: `${user.firstName} ${user.lastName}`, + disabled: true + }, + { + separator: true + }, + { + label: this.translateService.instant('header.change_password'), command: () => { + this.changePassword(); + }, + icon: 'pi pi-key' + }, + { + label: this.translateService.instant('header.settings'), command: () => { + this.userSettings(); + }, + icon: 'pi pi-cog' + }, + { + label: this.translateService.instant('header.logout'), command: () => { + this.logout(); + }, + icon: 'pi pi-sign-out' + } + ]; + }); + } + + initMenuLists(): void { + this.langList = [ + { + label: 'English', command: () => { + this.translate('en'); + this.setLang('en'); + }, + }, + { + label: 'Deutsch', command: () => { + this.translate('de'); + this.setLang('de'); + }, + }, + ]; + + this.initUserMenuList(); + + this.settings.getThemes()?.forEach(theme => { + this.themeList.push({ + label: theme.Label, + command: () => { + this.changeTheme(theme.Name); + } + }); + }); + } + + toggleMenu(): void { + this.themeService.setIsMenuOpen(!this.themeService.isSidebarOpen); + this.isSidebarFullWidth.emit(this.themeService.isSidebarOpen); + } + + changeTheme(name: string): void { + this.themeService.setTheme(name); + } + + changePassword(): void { + this.router.navigate(['/change-password']); + } + + userSettings(): void { + this.router.navigate(['/user-settings']); + } + + logout(): void { + this.authService.logout(); + } + + translate(lang: string) { + this.translateService.use(lang); + this.translateService.get('primeng').subscribe(res => this.config.setTranslation(res)); + } + + loadLang(): void { + const token = this.authService.getDecodedToken(); + const mail = this.authService.getEMailFromDecodedToken(token); + + if (!mail) { + this.translate('en'); + return; + } + + let lang = localStorage.getItem(`${mail}_lang`); + if (!lang) { + lang = 'en'; + this.setLang(lang); + } + this.translate(lang); + } + + setLang(lang: string): void { + this.authService.isUserLoggedInAsync().then(result => { + if (!result) { + return; + } + + const token = this.authService.getDecodedToken(); + const mail = this.authService.getEMailFromDecodedToken(token); + localStorage.setItem(`${mail}_lang`, lang); + }); + } + +} diff --git a/kdb-web/src/app/components/sidebar/sidebar.component.html b/kdb-web/src/app/components/sidebar/sidebar.component.html new file mode 100644 index 0000000000..b3bb4f3ba9 --- /dev/null +++ b/kdb-web/src/app/components/sidebar/sidebar.component.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/kdb-web/src/app/components/sidebar/sidebar.component.scss b/kdb-web/src/app/components/sidebar/sidebar.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-web/src/app/components/sidebar/sidebar.component.spec.ts b/kdb-web/src/app/components/sidebar/sidebar.component.spec.ts new file mode 100644 index 0000000000..1f932e2071 --- /dev/null +++ b/kdb-web/src/app/components/sidebar/sidebar.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SidebarComponent } from './sidebar.component'; + +describe('SidebarComponent', () => { + let component: SidebarComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ SidebarComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(SidebarComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/components/sidebar/sidebar.component.ts b/kdb-web/src/app/components/sidebar/sidebar.component.ts new file mode 100644 index 0000000000..a87eb35f74 --- /dev/null +++ b/kdb-web/src/app/components/sidebar/sidebar.component.ts @@ -0,0 +1,52 @@ +import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; +import { LangChangeEvent, TranslateService } from '@ngx-translate/core'; +import { MenuItem } from 'primeng/api'; +import { AuthRoles } from 'src/app/models/auth/auth-roles.enum'; +import { AuthService } from 'src/app/services/auth/auth.service'; + +@Component({ + selector: 'app-sidebar', + templateUrl: './sidebar.component.html', + styleUrls: ['./sidebar.component.scss'] +}) +export class SidebarComponent implements OnInit, OnChanges { + + @Input() isSidebarOpen!: boolean; + + menuItems!: MenuItem[]; + + constructor( + private authService: AuthService, + private translateService: TranslateService + ) { } + + ngOnInit(): void { + this.translateService.onLangChange.subscribe(async (event: LangChangeEvent) => { + await this.setMenu(this.isSidebarOpen); + }); + } + + async setMenu(isSidebarOpen: boolean) { + this.menuItems = []; + this.menuItems = [ + { label: isSidebarOpen ? this.translateService.instant('sidebar.dashboard') : '', icon: 'pi pi-th-large', routerLink: 'dashboard' }, + ]; + + if (await this.authService.hasUserPermission(AuthRoles.Admin)) { + this.menuItems.push( + { separator: true }, + { label: isSidebarOpen ? this.translateService.instant('sidebar.config') : '', icon: 'pi pi-cog', routerLink: '/admin/settings' }, + { label: isSidebarOpen ? this.translateService.instant('sidebar.auth_user_list') : '', icon: 'pi pi-user-edit', routerLink: '/admin/users' }, + ); + this.menuItems = this.menuItems.slice(); + } + } + + async ngOnChanges(changes: SimpleChanges): Promise { + if (!changes) + return; + + await this.setMenu(changes['isSidebarOpen'].currentValue); + } + +} diff --git a/kdb-web/src/app/components/spinner/spinner.component.html b/kdb-web/src/app/components/spinner/spinner.component.html new file mode 100644 index 0000000000..b4f52b87ee --- /dev/null +++ b/kdb-web/src/app/components/spinner/spinner.component.html @@ -0,0 +1,7 @@ + +
+
+ +
+
+
\ No newline at end of file diff --git a/kdb-web/src/app/components/spinner/spinner.component.scss b/kdb-web/src/app/components/spinner/spinner.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-web/src/app/components/spinner/spinner.component.spec.ts b/kdb-web/src/app/components/spinner/spinner.component.spec.ts new file mode 100644 index 0000000000..061f78d5e4 --- /dev/null +++ b/kdb-web/src/app/components/spinner/spinner.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SpinnerComponent } from './spinner.component'; + +describe('SpinnerComponent', () => { + let component: SpinnerComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ SpinnerComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(SpinnerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/components/spinner/spinner.component.ts b/kdb-web/src/app/components/spinner/spinner.component.ts new file mode 100644 index 0000000000..4753534cee --- /dev/null +++ b/kdb-web/src/app/components/spinner/spinner.component.ts @@ -0,0 +1,18 @@ +import { Component, OnInit } from '@angular/core'; +import { SpinnerService } from 'src/app/services/spinner/spinner.service'; + +@Component({ + selector: 'app-spinner', + templateUrl: './spinner.component.html', + styleUrls: ['./spinner.component.scss'] +}) +export class SpinnerComponent implements OnInit { + + constructor( + public spinnerService: SpinnerService + ) { } + + ngOnInit(): void { + } + +} diff --git a/kdb-web/src/app/models/auth/admin-update-user.dto.ts b/kdb-web/src/app/models/auth/admin-update-user.dto.ts new file mode 100644 index 0000000000..fe3222f56b --- /dev/null +++ b/kdb-web/src/app/models/auth/admin-update-user.dto.ts @@ -0,0 +1,7 @@ +import { AuthUserDTO } from "./auth-user.dto"; + +export interface AdminUpdateUserDTO { + authUserDTO: AuthUserDTO; + newAuthUserDTO: AuthUserDTO; + changePassword: boolean; +} \ No newline at end of file diff --git a/kdb-web/src/app/models/auth/auth-error-messages.enum.ts b/kdb-web/src/app/models/auth/auth-error-messages.enum.ts new file mode 100644 index 0000000000..4c3ebc390f --- /dev/null +++ b/kdb-web/src/app/models/auth/auth-error-messages.enum.ts @@ -0,0 +1,7 @@ +export enum AuthErrorMessages { + UserIsEmpty = "User is empty", + UserNotFound = "User not found", + WrongPassword = "Wrong password", + UserAlreadyExists = "User already exists", + EMailNotConfirmed = "E-Mail not confirmed" +} \ No newline at end of file diff --git a/kdb-web/src/app/models/auth/auth-roles.enum.ts b/kdb-web/src/app/models/auth/auth-roles.enum.ts new file mode 100644 index 0000000000..1bf2166d7f --- /dev/null +++ b/kdb-web/src/app/models/auth/auth-roles.enum.ts @@ -0,0 +1,4 @@ +export enum AuthRoles { + Normal = 0, + Admin = 1 +} diff --git a/kdb-web/src/app/models/auth/auth-user-atr-errors.ts b/kdb-web/src/app/models/auth/auth-user-atr-errors.ts new file mode 100644 index 0000000000..09394d9b57 --- /dev/null +++ b/kdb-web/src/app/models/auth/auth-user-atr-errors.ts @@ -0,0 +1,12 @@ +export class AuthUserAtrErrors { + firstName: AuthUserAtrErrorType = new AuthUserAtrErrorType(); + lastName: AuthUserAtrErrorType = new AuthUserAtrErrorType(); + email: AuthUserAtrErrorType = new AuthUserAtrErrorType(); + password: AuthUserAtrErrorType = new AuthUserAtrErrorType(); +} + +export class AuthUserAtrErrorType { + wrongData: boolean = false; + required: boolean = false; + notConfirmed: boolean = false; +} \ No newline at end of file diff --git a/kdb-web/src/app/models/auth/auth-user.dto.ts b/kdb-web/src/app/models/auth/auth-user.dto.ts new file mode 100644 index 0000000000..1760428884 --- /dev/null +++ b/kdb-web/src/app/models/auth/auth-user.dto.ts @@ -0,0 +1,11 @@ +import { AuthRoles } from "./auth-roles.enum"; + +export interface AuthUserDTO { + id?: number; + firstName: string | null; + lastName: string | null; + email: string | null; + password: string | null; + isConfirmed?: boolean + authRole?: AuthRoles; +} \ No newline at end of file diff --git a/kdb-web/src/app/models/auth/email-string.dto.ts b/kdb-web/src/app/models/auth/email-string.dto.ts new file mode 100644 index 0000000000..ffe000b843 --- /dev/null +++ b/kdb-web/src/app/models/auth/email-string.dto.ts @@ -0,0 +1,3 @@ +export interface EMailStringDTO { + email: string; +} \ No newline at end of file diff --git a/kdb-web/src/app/models/auth/register-error-messages.enum.ts b/kdb-web/src/app/models/auth/register-error-messages.enum.ts new file mode 100644 index 0000000000..31ffc50981 --- /dev/null +++ b/kdb-web/src/app/models/auth/register-error-messages.enum.ts @@ -0,0 +1,4 @@ +export enum RegisterErrorMessages { + InvalidEMail = "Invalid E-Mail", + UserAlreadyExists = "User already exists", +} \ No newline at end of file diff --git a/kdb-web/src/app/models/auth/reset-password.dto.ts b/kdb-web/src/app/models/auth/reset-password.dto.ts new file mode 100644 index 0000000000..669b349dbe --- /dev/null +++ b/kdb-web/src/app/models/auth/reset-password.dto.ts @@ -0,0 +1,6 @@ +import { AuthUserDTO } from "./auth-user.dto"; + +export interface ResetPasswordDTO { + id: string; + password: string; +} \ No newline at end of file diff --git a/kdb-web/src/app/models/auth/token.dto.ts b/kdb-web/src/app/models/auth/token.dto.ts new file mode 100644 index 0000000000..10e8b7c46a --- /dev/null +++ b/kdb-web/src/app/models/auth/token.dto.ts @@ -0,0 +1,4 @@ +export interface TokenDTO { + token: string; + refreshToken: string; +} \ No newline at end of file diff --git a/kdb-web/src/app/models/auth/update-user.dto.ts b/kdb-web/src/app/models/auth/update-user.dto.ts new file mode 100644 index 0000000000..15964af6c9 --- /dev/null +++ b/kdb-web/src/app/models/auth/update-user.dto.ts @@ -0,0 +1,6 @@ +import { AuthUserDTO } from "./auth-user.dto"; + +export interface UpdateUserDTO { + authUserDTO: AuthUserDTO; + newAuthUserDTO: AuthUserDTO; +} \ No newline at end of file diff --git a/kdb-web/src/app/models/config/api-version.ts b/kdb-web/src/app/models/config/api-version.ts new file mode 100644 index 0000000000..2de63b3334 --- /dev/null +++ b/kdb-web/src/app/models/config/api-version.ts @@ -0,0 +1,5 @@ +export interface ApiVersion { + Major: string; + Minor: string; + Micro: string; +} \ No newline at end of file diff --git a/kdb-web/src/app/models/config/appsettings.ts b/kdb-web/src/app/models/config/appsettings.ts new file mode 100644 index 0000000000..de434a03b7 --- /dev/null +++ b/kdb-web/src/app/models/config/appsettings.ts @@ -0,0 +1,8 @@ +import { SoftwareVersion } from "./software-version"; +import { Theme } from '../view/theme'; + +export interface Appsettings { + ApiURL: string; + WebVersion: SoftwareVersion; + Themes: Theme[]; +} \ No newline at end of file diff --git a/kdb-web/src/app/models/config/settings.dto.ts b/kdb-web/src/app/models/config/settings.dto.ts new file mode 100644 index 0000000000..825457c692 --- /dev/null +++ b/kdb-web/src/app/models/config/settings.dto.ts @@ -0,0 +1,16 @@ +export interface SettingsDTO { + webVersion: string; + apiVersion: string; + configPath: string; + webBaseURL: string; + apiBaseURL: string; + + tokenExpireTime: number; + refreshTokenExpireTime: number; + + mailUser: string; + mailPort: number; + mailHost: string; + mailTransceiver: string; + mailTransceiverAddress: string; +} \ No newline at end of file diff --git a/kdb-web/src/app/models/config/software-version.dto.ts b/kdb-web/src/app/models/config/software-version.dto.ts new file mode 100644 index 0000000000..6a6d51bd46 --- /dev/null +++ b/kdb-web/src/app/models/config/software-version.dto.ts @@ -0,0 +1,5 @@ +export interface SoftwareVersionDTO { + major: string; + minor: string; + micro: string +} \ No newline at end of file diff --git a/kdb-web/src/app/models/config/software-version.ts b/kdb-web/src/app/models/config/software-version.ts new file mode 100644 index 0000000000..4025b2b7ec --- /dev/null +++ b/kdb-web/src/app/models/config/software-version.ts @@ -0,0 +1,19 @@ +export class SoftwareVersion { + Major: string; + Minor: string; + Micro: string; + + constructor( + major: string, + minor: string, + micro: string + ) { + this.Major = major; + this.Minor = minor; + this.Micro = micro; + } + + getVersionString(): string { + return `${this.Major}.${this.Minor}.${this.Micro}`; + } +} \ No newline at end of file diff --git a/kdb-web/src/app/models/error/error-dto.ts b/kdb-web/src/app/models/error/error-dto.ts new file mode 100644 index 0000000000..14bffe773c --- /dev/null +++ b/kdb-web/src/app/models/error/error-dto.ts @@ -0,0 +1,8 @@ +import { ServiceErrorCode } from "./service-error-code.enum"; + + +export class ErrorDTO { + errorCode!: ServiceErrorCode; + message!: string; + +} diff --git a/kdb-web/src/app/models/error/service-error-code.enum.ts b/kdb-web/src/app/models/error/service-error-code.enum.ts new file mode 100644 index 0000000000..5853b5d8fe --- /dev/null +++ b/kdb-web/src/app/models/error/service-error-code.enum.ts @@ -0,0 +1,16 @@ +export enum ServiceErrorCode { + Unknown = 0, + + InvalidDependencies = 1, + InvalidData = 2, + NotFound = 3, + DataAlreadyExists = 4, + UnableToAdd = 5, + UnableToDelete = 6, + + InvalidUser = 7, + + ConnectionFailed = 8, + Timeout = 9, + MailError = 10 +} diff --git a/kdb-web/src/app/models/selection/auth-user/auth-user-select-criterion.dto.ts b/kdb-web/src/app/models/selection/auth-user/auth-user-select-criterion.dto.ts new file mode 100644 index 0000000000..a0e2455218 --- /dev/null +++ b/kdb-web/src/app/models/selection/auth-user/auth-user-select-criterion.dto.ts @@ -0,0 +1,8 @@ +import { SelectCriterion } from "../select-criterion.model"; + +export interface AuthUserSelectCriterion extends SelectCriterion { + firstName: string | null; + lastName: string | null; + email: string | null; + authRole?: number | null; +} \ No newline at end of file diff --git a/kdb-web/src/app/models/selection/auth-user/get-filtered-auth-users-result.dto.ts b/kdb-web/src/app/models/selection/auth-user/get-filtered-auth-users-result.dto.ts new file mode 100644 index 0000000000..23b8e9f824 --- /dev/null +++ b/kdb-web/src/app/models/selection/auth-user/get-filtered-auth-users-result.dto.ts @@ -0,0 +1,6 @@ +import { AuthUserDTO } from "../../auth/auth-user.dto"; + +export interface GetFilteredAuthUsersResultDTO { + users: AuthUserDTO[]; + totalCount: number; +} \ No newline at end of file diff --git a/kdb-web/src/app/models/selection/logins/login-select-criterion.dto.ts b/kdb-web/src/app/models/selection/logins/login-select-criterion.dto.ts new file mode 100644 index 0000000000..e1998d60bc --- /dev/null +++ b/kdb-web/src/app/models/selection/logins/login-select-criterion.dto.ts @@ -0,0 +1,8 @@ +import { SelectCriterion } from "../select-criterion.model"; + +export interface LoginSelectCriterion extends SelectCriterion { + timeFrom: string; + timeTo: string; + userName: string; + hostName: string; +} \ No newline at end of file diff --git a/kdb-web/src/app/models/selection/select-criterion.model.ts b/kdb-web/src/app/models/selection/select-criterion.model.ts new file mode 100644 index 0000000000..e6d29f3bfe --- /dev/null +++ b/kdb-web/src/app/models/selection/select-criterion.model.ts @@ -0,0 +1,6 @@ +export interface SelectCriterion { + pageIndex: number; + pageSize: number; + sortDirection: string | null; + sortColumn: string | null; +} \ No newline at end of file diff --git a/kdb-web/src/app/models/utils/confirmation-dialog.ts b/kdb-web/src/app/models/utils/confirmation-dialog.ts new file mode 100644 index 0000000000..8763a78ff1 --- /dev/null +++ b/kdb-web/src/app/models/utils/confirmation-dialog.ts @@ -0,0 +1,7 @@ +export interface ConfirmationDialog { + key?: string; + header: string; + message: string; + accept?: () => void; + reject?: () => void; +} diff --git a/kdb-web/src/app/models/utils/toast-options.ts b/kdb-web/src/app/models/utils/toast-options.ts new file mode 100644 index 0000000000..bde79a1b22 --- /dev/null +++ b/kdb-web/src/app/models/utils/toast-options.ts @@ -0,0 +1,5 @@ +export interface ToastOptions { + life?: number; + sticky?: boolean; + closable?: boolean; +} \ No newline at end of file diff --git a/kdb-web/src/app/models/view/theme.ts b/kdb-web/src/app/models/view/theme.ts new file mode 100644 index 0000000000..f918b2c334 --- /dev/null +++ b/kdb-web/src/app/models/view/theme.ts @@ -0,0 +1,4 @@ +export interface Theme { + Label: string; + Name: string; +} \ No newline at end of file diff --git a/kdb-web/src/app/models/view/themes.enum.ts b/kdb-web/src/app/models/view/themes.enum.ts new file mode 100644 index 0000000000..4aae8a533f --- /dev/null +++ b/kdb-web/src/app/models/view/themes.enum.ts @@ -0,0 +1,7 @@ +export enum Themes { + Default = "sh-edraft-dark-theme", + DefaultLight = "default-light-theme", + DefaultDark = "default-dark-theme", + ShEdraftLight = "sh-edraft-light-theme", + ShEdraftDark = "sh-edraft-dark-theme", +} \ No newline at end of file diff --git a/kdb-web/src/app/modules/admin/auth-users/auth-user-routing.module.ts b/kdb-web/src/app/modules/admin/auth-users/auth-user-routing.module.ts new file mode 100644 index 0000000000..3a10e506e1 --- /dev/null +++ b/kdb-web/src/app/modules/admin/auth-users/auth-user-routing.module.ts @@ -0,0 +1,13 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { AuthUserComponent } from './components/auth-user/auth-user.component'; + +const routes: Routes = [ + {path: '', component: AuthUserComponent} +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class AuthUserRoutingModule { } diff --git a/kdb-web/src/app/modules/admin/auth-users/auth-user.module.ts b/kdb-web/src/app/modules/admin/auth-users/auth-user.module.ts new file mode 100644 index 0000000000..c59463ac1d --- /dev/null +++ b/kdb-web/src/app/modules/admin/auth-users/auth-user.module.ts @@ -0,0 +1,18 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { AuthUserRoutingModule } from './auth-user-routing.module'; +import { AuthUserComponent } from './components/auth-user/auth-user.component'; +import { SharedModule } from '../../shared/shared.module'; + + +@NgModule({ + declarations: [ + AuthUserComponent + ], + imports: [ + CommonModule, + AuthUserRoutingModule, + SharedModule + ] +}) +export class AuthUserModule { } diff --git a/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.html b/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.html new file mode 100644 index 0000000000..1cb83a5569 --- /dev/null +++ b/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.html @@ -0,0 +1,201 @@ +

+ {{'admin.auth_users.header' | translate}} +

+
+
+ + + +
+
+ {{users.length}} {{'admin.auth_users.of' | translate}} + {{dt.totalRecords}} + + {{'admin.auth_users.users' | translate}} +
+ +
+ + +
+
+
+ + + + +
+
{{'admin.auth_users.headers.first_name' | translate}}
+ +
+ + + +
+
{{'admin.auth_users.headers.last_name' | translate}}
+ +
+ + + +
+
{{'admin.auth_users.headers.e_mail' | translate}}
+ +
+ + + +
+
{{'admin.auth_users.headers.active' | translate}}
+ +
+ + + +
+
{{'admin.auth_users.headers.role' | translate}}
+ +
+ + + +
+
{{'admin.auth_users.headers.password' | translate}}
+
+ + + +
+
{{'admin.auth_users.headers.actions' | translate}}
+
+ + + + +
+ +
+ + +
+ +
+ + +
+ +
+ + + +
+ +
+ + + + +
+ + + + + + + + + + {{user.firstName}} + + + + + + + + + + {{user.lastName}} + + + + + + + + + + {{user.email}} + + + + + + + + + + + + + + + + + + + + + + {{user.authRole | authRole}} + + + + + + + + + + + + + +
+ + + + + +
+ + +
+ + + + {{'admin.auth_users.no_entries_found' | translate}} + + + + + +
+
+
\ No newline at end of file diff --git a/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.scss b/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.spec.ts b/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.spec.ts new file mode 100644 index 0000000000..970536142c --- /dev/null +++ b/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AuthUserComponent } from './auth-user.component'; + +describe('AuthUserComponent', () => { + let component: AuthUserComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ AuthUserComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(AuthUserComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts b/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts new file mode 100644 index 0000000000..598b18d4fe --- /dev/null +++ b/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts @@ -0,0 +1,330 @@ +import { Component, OnInit } from '@angular/core'; +import { catchError, debounceTime, last } from 'rxjs/operators'; +import { AuthRoles } from 'src/app/models/auth/auth-roles.enum'; +import { AuthUserDTO } from 'src/app/models/auth/auth-user.dto'; +import { AuthService } from 'src/app/services/auth/auth.service'; +import { ConfirmationDialogService } from 'src/app/services/confirmation-dialog/confirmation-dialog.service'; +import { SpinnerService } from 'src/app/services/spinner/spinner.service'; +import { ToastService } from 'src/app/services/toast/toast.service'; +import { Table } from 'primeng/table'; +import { ServiceErrorCode } from 'src/app/models/error/service-error-code.enum'; +import { RegisterErrorMessages } from 'src/app/models/auth/register-error-messages.enum'; +import { ErrorDTO } from 'src/app/models/error/error-dto'; +import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; +import { AuthUserSelectCriterion } from 'src/app/models/selection/auth-user/auth-user-select-criterion.dto'; +import { LazyLoadEvent } from 'primeng/api'; +import { throwError } from 'rxjs'; +import { TranslateService } from '@ngx-translate/core'; + + +@Component({ + selector: 'app-auth-user', + templateUrl: './auth-user.component.html', + styleUrls: ['./auth-user.component.scss'] +}) +export class AuthUserComponent implements OnInit { + + users!: AuthUserDTO[]; + statuses!: any[]; + loading = true; + activityValues: number[] = [0, 100]; + + clonedUsers: { [s: string]: AuthUserDTO; } = {}; + isEditingNew: boolean = false; + + authRoles = [ + { label: AuthRoles[AuthRoles.Normal].toString(), value: AuthRoles.Normal }, + { label: AuthRoles[AuthRoles.Admin].toString(), value: AuthRoles.Admin } + ] + + newUserTemplate: AuthUserDTO = { + id: 0, + firstName: "", + lastName: "", + email: "", + password: "", + authRole: AuthRoles.Normal + }; + + isFirstNameInvalid: boolean = false; + isLastNameInvalid: boolean = false; + isEMailInvalid: boolean = false; + isPasswordInvalid: boolean = false; + + loggedInUserEMail: string = ""; + + filterForm!: FormGroup<{ + firstName: FormControl, + lastName: FormControl, + email: FormControl, + authRole: FormControl + }>; + searchCriterions!: AuthUserSelectCriterion; + totalRecords!: number; + + constructor( + private authService: AuthService, + private spinnerService: SpinnerService, + private toastService: ToastService, + private confirmDialog: ConfirmationDialogService, + private fb: FormBuilder, + private translate: TranslateService + ) { } + + ngOnInit(): void { + this.loggedInUserEMail = this.authService.getEMailFromDecodedToken(this.authService.getDecodedToken()) ?? ''; + this.searchCriterions = { + firstName: null, + lastName: null, + email: null, + authRole: null, + pageIndex: 0, + pageSize: 10, + sortColumn: null, + sortDirection: null + }; + + this.setFilterForm(); + // this.loadNextPage(); + } + + setFilterForm() { + this.filterForm = this.fb.group({ + firstName: [''], + lastName: [''], + email: [''], + authRole: [''] + }); + + this.filterForm.valueChanges.pipe( + debounceTime(600) + ).subscribe(changes => { + if (changes.firstName) { + this.searchCriterions.firstName = changes.firstName; + } else { + this.searchCriterions.firstName = null; + } + + if (changes.lastName) { + this.searchCriterions.lastName = changes.lastName; + } else { + this.searchCriterions.lastName = null; + } + + if (changes.email) { + this.searchCriterions.email = changes.email; + } else { + this.searchCriterions.email = null; + } + + if (changes.authRole != null) { + this.searchCriterions.authRole = +changes.authRole; + } else { + this.searchCriterions.authRole = null; + } + + if (this.searchCriterions.pageSize) + this.searchCriterions.pageSize = 10; + + if (this.searchCriterions.pageSize) + this.searchCriterions.pageIndex = 0; + + this.loadNextPage(); + }); + } + + loadNextPage() { + this.authService.getFilteredUsers(this.searchCriterions).pipe(catchError(err => { + this.loading = false; + return throwError(err); + })).subscribe(list => { + this.totalRecords = list.totalCount; + this.users = list.users; + this.loading = false; + }); + } + + nextPage(event: LazyLoadEvent) { + this.searchCriterions.pageSize = event.rows ?? 0; + if (event.first != null && event.rows != null) + this.searchCriterions.pageIndex = event.first / event.rows; + this.searchCriterions.sortColumn = event.sortField ?? null; + this.searchCriterions.sortDirection = event.sortOrder === 1 ? 'asc' : event.sortOrder === -1 ? 'desc' : 'asc'; + + if (event.filters) { + // + "" => convert to string + this.searchCriterions.firstName = event.filters['firstName'] ? event.filters['firstName'] + "" : null; + this.searchCriterions.lastName = event.filters['lastName'] ? event.filters['lastName'] + "" : null; + this.searchCriterions.email = event.filters['email'] ? event.filters['email'] + "" : null; + this.searchCriterions.authRole = event.filters['authRole'] ? +event.filters['authRole'] : null; + } + + this.loadNextPage(); + } + + resetFilters(table: Table) { + this.filterForm.reset(); + } + + initUserList(): void { + this.spinnerService.showSpinner(); + this.authService.getAllUsers() + .pipe(catchError(err => { + this.spinnerService.hideSpinner(); + throw err; + })) + .subscribe(users => { + this.users = users; + this.spinnerService.hideSpinner(); + }); + } + + onRowEditInit(table: Table, user: AuthUserDTO, index: number) { + this.clonedUsers[index] = { ...user }; + } + + onRowEditSave(table: Table, newUser: AuthUserDTO, index: number) { + const oldUser = this.clonedUsers[index]; + delete this.clonedUsers[index]; + + if (JSON.stringify(oldUser) === JSON.stringify(newUser) && !this.isEditingNew) { + return; + } + + if (this.isEditingNew && JSON.stringify(newUser) === JSON.stringify(this.newUserTemplate)) { + this.isEditingNew = false; + this.users.splice(index, 1); + return; + } + + this.isFirstNameInvalid = newUser.firstName == ""; + this.isLastNameInvalid = newUser.lastName == ""; + this.isEMailInvalid = newUser.email == ""; + this.isPasswordInvalid = newUser.password == ""; + + if ( + this.isEditingNew && ( + newUser.firstName == "" || + newUser.lastName == "" || + newUser.email == "" + ) + ) { + table.initRowEdit(newUser); + return; + } + + if (this.isEditingNew) { + this.spinnerService.showSpinner(); + this.authService.register(newUser).pipe(catchError(error => { + this.spinnerService.hideSpinner(); + + if (error.error !== null) { + const err: ErrorDTO = error.error; + + if (err.errorCode === ServiceErrorCode.InvalidData && err.message === RegisterErrorMessages.InvalidEMail) { + this.isEMailInvalid = true; + this.toastService.error(this.translate.instant('admin.auth_users.message.invalid_email'), this.translate.instant('admin.auth_users.message.invalid_email_d', { email: newUser.email })); + } else if (err.errorCode === ServiceErrorCode.InvalidUser && err.message === RegisterErrorMessages.UserAlreadyExists) { + this.isEMailInvalid = true; + this.toastService.error(this.translate.instant('admin.auth_users.message.user_already_exists'), this.translate.instant('admin.auth_users.message.user_already_exists_d', { email: newUser.email })); + } + error.error = null; + table.initRowEdit(newUser); + } + this.spinnerService.hideSpinner(); + + throw error; + })) + .subscribe(_ => { + this.initUserList(); + this.spinnerService.hideSpinner(); + this.toastService.success(this.translate.instant('admin.auth_users.message.user_added'), this.translate.instant('admin.auth_users.message.user_added_d', { email: newUser.email })); + this.isEditingNew = false; + }); + this.triggerUserChangeDetection(); + return; + } + + this.spinnerService.showSpinner(); + this.authService.updateUserAsAdmin({ + authUserDTO: oldUser, + newAuthUserDTO: newUser, + changePassword: newUser.password != "" + }).pipe(catchError(err => { + this.spinnerService.hideSpinner(); + this.toastService.error(this.translate.instant('admin.auth_users.message.user_change_failed'), this.translate.instant('admin.auth_users.message.user_change_failed_d', { email: newUser.email })); + this.initUserList(); + throw err; + })) + .subscribe(_ => { + this.initUserList(); + this.spinnerService.hideSpinner(); + this.toastService.success(this.translate.instant('admin.auth_users.message.user_changed'), this.translate.instant('admin.auth_users.message.user_changed_d', { email: newUser.email })); + }); + this.triggerUserChangeDetection(); + } + + onRowEditCancel(user: AuthUserDTO, index: number) { + this.isFirstNameInvalid = false; + this.isLastNameInvalid = false; + this.isEMailInvalid = false; + this.isPasswordInvalid = false; + + if (this.isEditingNew) { + this.users.splice(index, 1); + this.triggerUserChangeDetection(); + delete this.clonedUsers[index]; + this.isEditingNew = false; + return; + } + + this.users[index] = this.clonedUsers[index]; + this.triggerUserChangeDetection(); + delete this.clonedUsers[index]; + } + + deleteUser(user: AuthUserDTO) { + if (user.email == this.loggedInUserEMail) { + this.toastService.error(this.translate.instant('admin.auth_users.message.cannot_delete_user'), this.translate.instant('admin.auth_users.message.logon_with_another_user')); + return; + } + + this.confirmDialog.confirmDialog( + this.translate.instant('admin.auth_users.message.user_delete'), this.translate.instant('admin.auth_users.message.user_delete_q', { email: user.email }), + () => { + this.spinnerService.showSpinner(); + this.authService.deleteUserByMail(user.email ?? '') + .pipe(catchError(err => { + this.spinnerService.hideSpinner(); + throw err; + })) + .subscribe(_ => { + this.initUserList(); + this.spinnerService.hideSpinner(); + this.toastService.success(this.translate.instant('admin.auth_users.message.user_deleted'), this.translate.instant('admin.auth_users.message.user_deleted_d', { email: user.email })); + }); + }); + } + + addUser(table: Table) { + const newUser = JSON.parse(JSON.stringify(this.newUserTemplate)); + newUser.id = Math.max.apply(Math, this.users.map(u => { return u.id ?? 0; })) + 1; + console.log(newUser); + + this.users.push(newUser); + this.triggerUserChangeDetection(); + + table.initRowEdit(newUser); + + const index = this.users.findIndex(u => u.email == newUser.email); + this.onRowEditInit(table, newUser, index); + + this.isEditingNew = true; + } + + triggerUserChangeDetection() { + // trigger change detection (https://github.com/primefaces/primeng/issues/2219) + this.users = this.users.slice(); + } + +} diff --git a/kdb-web/src/app/modules/admin/settings/components/settings/settings.component.html b/kdb-web/src/app/modules/admin/settings/components/settings/settings.component.html new file mode 100644 index 0000000000..067d3ebb80 --- /dev/null +++ b/kdb-web/src/app/modules/admin/settings/components/settings/settings.component.html @@ -0,0 +1,125 @@ +

+ {{'admin.settings.header' | translate}} +

+
+
+

+ {{'admin.settings.website.header' | translate}} +

+
+ +
+
+
+
{{'admin.settings.website.frontend_version' | translate}}:
+
{{data.webVersion}}
+
+
+ +
+
+
{{'admin.settings.website.backend_version' | translate}}:
+
{{data.apiVersion}}
+
+
+ +
+
+
{{'admin.settings.website.config_path' | translate}}:
+
{{data.configPath}}
+
+
+ +
+
+
{{'admin.settings.website.frontend_base_url' | translate}}:
+
{{data.webBaseURL}}
+
+
+ +
+
+
{{'admin.settings.website.backend_base_url' | translate}}:
+
{{data.apiBaseURL}}
+
+
+ +
+ +
+
+
{{'admin.settings.website.token_expire_time' | translate}}:
+
{{data.tokenExpireTime}} {{'general.minutes' | translate}}
+
+
+ +
+
+
{{'admin.settings.website.refresh_token_expire_time' | translate}}:
+
{{data.refreshTokenExpireTime}} {{'general.days' | translate}}
+
+
+
+
+ +
+
+

+ {{'admin.settings.e_mail.header' | translate}} +

+
+ +
+
+
+
{{'admin.settings.e_mail.user' | translate}}:
+
{{data.mailUser}}
+
+
+ +
+
+
{{'admin.settings.e_mail.host' | translate}}:
+
{{data.mailHost}}
+
+
+ +
+
+
{{'admin.settings.e_mail.port' | translate}}:
+
{{data.mailPort}}
+
+
+ +
+
+
{{'admin.settings.e_mail.transceiver' | translate}}:
+
{{data.mailTransceiver}}
+
+
+ +
+
+
{{'admin.settings.e_mail.e_mail_address' | translate}}:
+
{{data.mailTransceiverAddress}}
+
+
+ +
+
+
+
+ +
+
+ +
+ +
+
+
+
+
\ No newline at end of file diff --git a/kdb-web/src/app/modules/admin/settings/components/settings/settings.component.scss b/kdb-web/src/app/modules/admin/settings/components/settings/settings.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-web/src/app/modules/admin/settings/components/settings/settings.component.spec.ts b/kdb-web/src/app/modules/admin/settings/components/settings/settings.component.spec.ts new file mode 100644 index 0000000000..a3a508b0ee --- /dev/null +++ b/kdb-web/src/app/modules/admin/settings/components/settings/settings.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SettingsComponent } from './settings.component'; + +describe('SettingsComponent', () => { + let component: SettingsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ SettingsComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(SettingsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/modules/admin/settings/components/settings/settings.component.ts b/kdb-web/src/app/modules/admin/settings/components/settings/settings.component.ts new file mode 100644 index 0000000000..020a8f0ef9 --- /dev/null +++ b/kdb-web/src/app/modules/admin/settings/components/settings/settings.component.ts @@ -0,0 +1,121 @@ +import { Component, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { TranslateService } from '@ngx-translate/core'; +import { catchError } from 'rxjs/operators'; +import { SettingsDTO } from 'src/app/models/config/settings.dto'; +import { ErrorDTO } from 'src/app/models/error/error-dto'; +import { ServiceErrorCode } from 'src/app/models/error/service-error-code.enum'; +import { AuthService } from 'src/app/services/auth/auth.service'; +import { GuiService } from 'src/app/services/gui/gui.service'; +import { SettingsService } from 'src/app/services/settings/settings.service'; +import { SpinnerService } from 'src/app/services/spinner/spinner.service'; +import { ToastService } from 'src/app/services/toast/toast.service'; + +@Component({ + selector: 'app-settings', + templateUrl: './settings.component.html', + styleUrls: ['./settings.component.scss'] +}) +export class SettingsComponent implements OnInit { + + testMailForm!: FormGroup; + data: SettingsDTO = { + webVersion: '', + apiVersion: '', + configPath: '', + webBaseURL: '', + apiBaseURL: '', + + tokenExpireTime: 0, + refreshTokenExpireTime: 0, + + mailUser: '', + mailPort: 0, + mailHost: '', + mailTransceiver: '', + mailTransceiverAddress: '', + }; + + constructor( + private settingsService: SettingsService, + private spinnerService: SpinnerService, + private guiService: GuiService, + private formBuilder: FormBuilder, + private toastService: ToastService, + private translate: TranslateService + ) { } + + ngOnInit(): void { + this.spinnerService.showSpinner(); + this.initForms(); + + this.guiService.getSettings() + .pipe(catchError(err => { + this.spinnerService.hideSpinner(); + throw err; + })) + .subscribe(settings => { + this.spinnerService.hideSpinner(); + this.data = settings; + this.data.webVersion = this.settingsService.getWebVersion()?.getVersionString() ?? '0.0.0'; + this.data.apiBaseURL = this.settingsService.getApiURL(); + if (!this.data.apiBaseURL.endsWith('/')) { + this.data.apiBaseURL += '/'; + } + }); + } + + initForms(): void { + this.testMailForm = this.formBuilder.group({ + mail: [null, [Validators.required, Validators.email]], + }); + } + + testMail(): void { + this.spinnerService.showSpinner(); + + const mail = this.testMailForm.value.mail; + if (!mail) { + this.spinnerService.hideSpinner(); + return; + } + + this.guiService.sendTestMail(mail) + .pipe(catchError(error => { + let header = this.translate.instant('admin.settings.message.error'); + let message = this.translate.instant('admin.settings.message.could_not_send_mail'); + + if (error.error !== null) { + const err: ErrorDTO = error.error; + + if (err.errorCode === ServiceErrorCode.ConnectionFailed) { + header = this.translate.instant('admin.settings.message.connection_failed'); + message = this.translate.instant('admin.settings.message.connection_to_mail_failed'); + error.error = null; + } + + if (err.errorCode === ServiceErrorCode.InvalidUser) { + header = this.translate.instant('admin.settings.message.connection_failed'); + message = this.translate.instant('admin.settings.message.mail_login_failed'); + error.error = null; + } + + if (err.errorCode === ServiceErrorCode.MailError) { + header = this.translate.instant('admin.settings.message.send_failed'); + message = this.translate.instant('admin.settings.message.test_mail_not_send'); + error.error = null; + } + } + + this.spinnerService.hideSpinner(); + this.toastService.error(header, message); + throw error; + })) + .subscribe(res => { + this.spinnerService.hideSpinner(); + this.toastService.success(this.translate.instant('admin.settings.message.success'), this.translate.instant('admin.settings.message.send_mail')); + this.testMailForm.reset(); + }); + } + +} diff --git a/kdb-web/src/app/modules/admin/settings/settings-routing.module.ts b/kdb-web/src/app/modules/admin/settings/settings-routing.module.ts new file mode 100644 index 0000000000..12585a86d3 --- /dev/null +++ b/kdb-web/src/app/modules/admin/settings/settings-routing.module.ts @@ -0,0 +1,13 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { SettingsComponent } from './components/settings/settings.component'; + +const routes: Routes = [ + {path:'', component: SettingsComponent} +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class SettingsRoutingModule { } diff --git a/kdb-web/src/app/modules/admin/settings/settings.module.ts b/kdb-web/src/app/modules/admin/settings/settings.module.ts new file mode 100644 index 0000000000..3eae81064b --- /dev/null +++ b/kdb-web/src/app/modules/admin/settings/settings.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { SettingsRoutingModule } from './settings-routing.module'; +import { SettingsComponent } from './components/settings/settings.component'; +import { SharedModule } from '../../shared/shared.module'; + + +@NgModule({ + declarations: [ + SettingsComponent + ], + imports: [ + CommonModule, + SettingsRoutingModule, + SharedModule + ] +}) +export class SettingsModule { } diff --git a/kdb-web/src/app/modules/auth/auth-routing.module.ts b/kdb-web/src/app/modules/auth/auth-routing.module.ts new file mode 100644 index 0000000000..d19b6a528c --- /dev/null +++ b/kdb-web/src/app/modules/auth/auth-routing.module.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { ForgetPasswordComponent } from './components/forget-password/forget-password.component'; +import { LoginComponent } from './components/login/login.component'; +import { RegistrationComponent } from './components/registration/registration.component'; + +const routes: Routes = [ + { path: 'login', component: LoginComponent }, + { path: 'register', component: RegistrationComponent }, + { path: 'register/:id', component: RegistrationComponent }, + { path: 'forgot-password', component: ForgetPasswordComponent }, + { path: 'forgot-password/:id', component: ForgetPasswordComponent }, + { path: 'forgot-password', component: ForgetPasswordComponent }, + { path: 'forgot-password/:id', component: ForgetPasswordComponent }, +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class AuthRoutingModule { } diff --git a/kdb-web/src/app/modules/auth/auth.module.ts b/kdb-web/src/app/modules/auth/auth.module.ts new file mode 100644 index 0000000000..4e7c48c3a7 --- /dev/null +++ b/kdb-web/src/app/modules/auth/auth.module.ts @@ -0,0 +1,23 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { AuthRoutingModule } from './auth-routing.module'; +import { ForgetPasswordComponent } from './components/forget-password/forget-password.component'; +import { LoginComponent } from './components/login/login.component'; +import { RegistrationComponent } from './components/registration/registration.component'; +import { SharedModule } from '../shared/shared.module'; + + +@NgModule({ + declarations: [ + ForgetPasswordComponent, + LoginComponent, + RegistrationComponent + ], + imports: [ + CommonModule, + AuthRoutingModule, + SharedModule + ] +}) +export class AuthModule { } diff --git a/kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.html b/kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.html new file mode 100644 index 0000000000..e1fee63eab --- /dev/null +++ b/kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.html @@ -0,0 +1,57 @@ + \ No newline at end of file diff --git a/kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.scss b/kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.spec.ts b/kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.spec.ts new file mode 100644 index 0000000000..701620a945 --- /dev/null +++ b/kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ForgetPasswordComponent } from './forget-password.component'; + +describe('ForgetPasswordComponent', () => { + let component: ForgetPasswordComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ForgetPasswordComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ForgetPasswordComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.ts b/kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.ts new file mode 100644 index 0000000000..c49c6be16f --- /dev/null +++ b/kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.ts @@ -0,0 +1,136 @@ +import { Component, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { ActivatedRoute, Router } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; +import { catchError } from 'rxjs/operators'; +import { ResetPasswordDTO } from 'src/app/models/auth/reset-password.dto'; +import { AuthService } from 'src/app/services/auth/auth.service'; +import { SpinnerService } from 'src/app/services/spinner/spinner.service'; +import { ToastService } from 'src/app/services/toast/toast.service'; + +@Component({ + selector: 'app-forget-password', + templateUrl: './forget-password.component.html', + styleUrls: ['./forget-password.component.scss'] +}) +export class ForgetPasswordComponent implements OnInit { + + emailForm!: FormGroup; + passwordForm!: FormGroup; + submitted = false; + ready = false; + repeatErrors = { + email: false, + password: false + }; + + resetPasswordId: string | null = null; + + constructor( + private authService: AuthService, + private formBuilder: FormBuilder, + private router: Router, + private spinnerService: SpinnerService, + private route: ActivatedRoute, + private toastService: ToastService, + private translate: TranslateService + ) { } + + ngOnInit(): void { + this.spinnerService.showSpinner(); + this.authService.isUserLoggedInAsync().then(result => { + if (result) { + this.router.navigate(['/dashboard']); + } + + this.initForms(); + this.checkResetPasswordId(); + this.spinnerService.hideSpinner(); + }); + } + + initForms(): void { + this.emailForm = this.formBuilder.group({ + email: [null, [Validators.required, Validators.email]] + }); + + this.passwordForm = this.formBuilder.group({ + password: [null, [Validators.required, Validators.minLength(8)]], + passwordRepeat: [null, [Validators.required, Validators.minLength(8)]] + }); + } + + login(): void { + this.router.navigate(['/auth/login']); + } + + register(): void { + this.router.navigate(['/auth/register']); + } + + forgotPassword(): void { + this.submitted = true; + + if (this.emailForm.invalid) { + return; + } + + this.spinnerService.showSpinner(); + this.authService.forgotPassword(this.emailForm.value.email) + .pipe(catchError(err => { + this.spinnerService.hideSpinner(); + throw err; + })).subscribe(res => { + this.spinnerService.hideSpinner(); + this.ready = true; + setTimeout(() => { this.router.navigate(['/dashboard']); }, 5000); + }); + } + + checkResetPasswordId(): void { + const id = this.route.snapshot.params['id']; + if (id) { + this.resetPasswordId = id; + this.spinnerService.showSpinner(); + this.authService.getEMailFromforgotPasswordId(id) + .pipe(catchError(err => { + this.spinnerService.hideSpinner(); + this.router.navigate(['/auth/forgot-password']); + throw err; + })).subscribe(email => { + this.spinnerService.hideSpinner(); + if (email) { + this.emailForm.value.email = email; + } else { + this.router.navigate(['/auth/forgot-password']); + } + }); + } + } + + resetPassword(): void { + const id = this.route.snapshot.params['id']; + if (this.emailForm.value.password !== this.emailForm.value.passwordRepeat) { + this.repeatErrors.password = true; + return; + } + this.spinnerService.showSpinner(); + + const resetPasswordDTO: ResetPasswordDTO = { + id, + password: this.passwordForm.value.password + }; + + this.authService.resetPassword(resetPasswordDTO) + .pipe(catchError(error => { + this.router.navigate(['/auth/login']); + this.spinnerService.hideSpinner(); + throw error; + })) + .subscribe(resp => { + this.spinnerService.hideSpinner(); + this.toastService.success(this.translate.instant('auth.forgot_password.message.reset_password'), this.translate.instant('auth.forgot_password.message.reset_password_d')); + this.router.navigate(['/auth/login']); + }); + } +} diff --git a/kdb-web/src/app/modules/auth/components/login/login.component.html b/kdb-web/src/app/modules/auth/components/login/login.component.html new file mode 100644 index 0000000000..43ea33cdde --- /dev/null +++ b/kdb-web/src/app/modules/auth/components/login/login.component.html @@ -0,0 +1,58 @@ + \ No newline at end of file diff --git a/kdb-web/src/app/modules/auth/components/login/login.component.scss b/kdb-web/src/app/modules/auth/components/login/login.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-web/src/app/modules/auth/components/login/login.component.spec.ts b/kdb-web/src/app/modules/auth/components/login/login.component.spec.ts new file mode 100644 index 0000000000..d2c0e6c8fd --- /dev/null +++ b/kdb-web/src/app/modules/auth/components/login/login.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LoginComponent } from './login.component'; + +describe('LoginComponent', () => { + let component: LoginComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ LoginComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(LoginComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/modules/auth/components/login/login.component.ts b/kdb-web/src/app/modules/auth/components/login/login.component.ts new file mode 100644 index 0000000000..4a073c9afb --- /dev/null +++ b/kdb-web/src/app/modules/auth/components/login/login.component.ts @@ -0,0 +1,114 @@ +import { Component, OnInit } from '@angular/core'; +import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { AuthService } from 'src/app/services/auth/auth.service'; +import { AuthUserDTO } from 'src/app/models/auth/auth-user.dto'; +import { Router } from '@angular/router'; +import { catchError } from 'rxjs/operators'; +import { ErrorDTO } from 'src/app/models/error/error-dto'; +import { AuthErrorMessages } from 'src/app/models/auth/auth-error-messages.enum'; +import { ServiceErrorCode } from 'src/app/models/error/service-error-code.enum'; +import { AuthUserAtrErrors } from 'src/app/models/auth/auth-user-atr-errors'; +import { SpinnerService } from 'src/app/services/spinner/spinner.service'; +import { ThemeService } from 'src/app/services/theme/theme.service'; + +@Component({ + selector: 'app-login', + templateUrl: './login.component.html', + styleUrls: ['./login.component.scss'] +}) +export class LoginComponent implements OnInit { + + loginForm!: FormGroup<{ + email: FormControl, + password: FormControl + }>; + submitted = false; + + authUserAtrErrors!: AuthUserAtrErrors; + + constructor( + private authService: AuthService, + private formBuilder: FormBuilder, + private router: Router, + private spinnerService: SpinnerService, + private themeService: ThemeService + ) { } + + ngOnInit(): void { + this.spinnerService.showSpinner(); + this.authService.isUserLoggedInAsync().then(result => { + if (result) { + this.router.navigate(['/dashboard']); + } + + this.initLoginForm(); + this.resetStateFlags(); + this.spinnerService.hideSpinner(); + }); + } + + resetStateFlags(): void { + this.authUserAtrErrors = new AuthUserAtrErrors(); + } + + initLoginForm(): void { + this.loginForm = this.formBuilder.group({ + email: ['', [Validators.required, Validators.email]], + password: ['', [Validators.required, Validators.minLength(8)]] + }); + } + + register(): void { + this.router.navigate(['/auth/register']); + } + + forgotPassword(): void { + this.router.navigate(['/auth/forgot-password']); + } + + login(): void { + this.submitted = true; + this.resetStateFlags(); + + if (this.loginForm.invalid) { + return; + } + + this.spinnerService.showSpinner(); + const user: AuthUserDTO = { + firstName: '', + lastName: '', + email: this.loginForm.value.email ?? null, + password: this.loginForm.value.password ?? null + }; + + this.authService.login(user) + .pipe(catchError(error => { + if (error.error !== null) { + const err: ErrorDTO = error.error; + + if (err.errorCode === ServiceErrorCode.InvalidData && err.message === AuthErrorMessages.UserIsEmpty) { + this.authUserAtrErrors.email.required = true; + this.authUserAtrErrors.password.required = true; + } else if (err.errorCode === ServiceErrorCode.InvalidUser && err.message === AuthErrorMessages.UserNotFound) { + this.authUserAtrErrors.email.wrongData = true; + } else if (err.errorCode === ServiceErrorCode.InvalidUser && err.message === AuthErrorMessages.WrongPassword) { + this.authUserAtrErrors.password.wrongData = true; + } else if (err.errorCode === ServiceErrorCode.InvalidUser && err.message === AuthErrorMessages.EMailNotConfirmed) { + this.authUserAtrErrors.email.notConfirmed = true; + } + error.error = null; + } + this.spinnerService.hideSpinner(); + throw error; + })) + .subscribe(token => { + this.authService.saveToken(token); + this.themeService.loadTheme(); + this.themeService.loadMenu(); + this.spinnerService.hideSpinner(); + this.router.navigate(['/dashboard']); + }); + } + +} diff --git a/kdb-web/src/app/modules/auth/components/registration/registration.component.html b/kdb-web/src/app/modules/auth/components/registration/registration.component.html new file mode 100644 index 0000000000..2d9f41bdc5 --- /dev/null +++ b/kdb-web/src/app/modules/auth/components/registration/registration.component.html @@ -0,0 +1,83 @@ + \ No newline at end of file diff --git a/kdb-web/src/app/modules/auth/components/registration/registration.component.scss b/kdb-web/src/app/modules/auth/components/registration/registration.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-web/src/app/modules/auth/components/registration/registration.component.spec.ts b/kdb-web/src/app/modules/auth/components/registration/registration.component.spec.ts new file mode 100644 index 0000000000..6c3a576f97 --- /dev/null +++ b/kdb-web/src/app/modules/auth/components/registration/registration.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { RegistrationComponent } from './registration.component'; + +describe('RegistrationComponent', () => { + let component: RegistrationComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ RegistrationComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(RegistrationComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/modules/auth/components/registration/registration.component.ts b/kdb-web/src/app/modules/auth/components/registration/registration.component.ts new file mode 100644 index 0000000000..3cd29c1444 --- /dev/null +++ b/kdb-web/src/app/modules/auth/components/registration/registration.component.ts @@ -0,0 +1,144 @@ +import { Component, OnInit } from '@angular/core'; +import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { ActivatedRoute, Router } from '@angular/router'; +import { catchError } from 'rxjs/operators'; +import { AuthErrorMessages } from 'src/app/models/auth/auth-error-messages.enum'; +import { AuthUserDTO } from 'src/app/models/auth/auth-user.dto'; +import { AuthUserAtrErrors } from 'src/app/models/auth/auth-user-atr-errors'; +import { ErrorDTO } from 'src/app/models/error/error-dto'; +import { ServiceErrorCode } from 'src/app/models/error/service-error-code.enum'; +import { AuthService } from 'src/app/services/auth/auth.service'; +import { SpinnerService } from 'src/app/services/spinner/spinner.service'; + +@Component({ + selector: 'app-registration', + templateUrl: './registration.component.html', + styleUrls: ['./registration.component.scss'] +}) +export class RegistrationComponent implements OnInit { + + loginForm!: FormGroup<{ + firstName: FormControl, + lastName: FormControl, + email: FormControl, + emailRepeat: FormControl, + password: FormControl, + passwordRepeat: FormControl + }>; + submitted = false; + authUserAtrErrors!: AuthUserAtrErrors; + repeatErrors = { + email: false, + password: false + }; + + showEMailConfirmation = false; + showEMailConfirmationError = false; + + constructor( + private authService: AuthService, + private formBuilder: FormBuilder, + private router: Router, + private spinnerService: SpinnerService, + private route: ActivatedRoute + ) { + this.spinnerService.showSpinner(); + this.authService.isUserLoggedInAsync().then(res => { + if (res) { + this.router.navigate(['/dashboard']); + } + this.spinnerService.hideSpinner(); + }); + } + + ngOnInit(): void { + this.initLoginForm(); + this.resetStateFlags(); + this.confirmEMail(); + } + + resetStateFlags(): void { + this.authUserAtrErrors = new AuthUserAtrErrors(); + this.repeatErrors = { + email: false, + password: false + }; + } + + login(): void { + this.router.navigate(['/auth/login']); + } + + initLoginForm(): void { + this.loginForm = this.formBuilder.group({ + firstName: ['', Validators.required], + lastName: ['', Validators.required], + email: ['', [Validators.required, Validators.email]], + emailRepeat: ['', [Validators.required, Validators.email]], + password: ['', [Validators.required, Validators.minLength(8)]], + passwordRepeat: ['', [Validators.required, Validators.minLength(8)]] + }); + } + + register(): void { + this.submitted = true; + this.resetStateFlags(); + + // stop here if form is invalid + if (this.loginForm.invalid) { + return; + } + + if (this.loginForm.value.email !== this.loginForm.value.emailRepeat) { + this.repeatErrors.email = true; + return; + } + + if (this.loginForm.value.password !== this.loginForm.value.passwordRepeat) { + this.repeatErrors.password = true; + return; + } + + this.spinnerService.showSpinner(); + const user: AuthUserDTO = { + firstName: this.loginForm.value.firstName ?? null, + lastName: this.loginForm.value.lastName ?? null, + email: this.loginForm.value.email ?? null, + password: this.loginForm.value.password ?? null + }; + + this.authService.register(user) + .pipe(catchError(error => { + if (error.error !== null) { + const err: ErrorDTO = error.error; + + if (err.errorCode === ServiceErrorCode.InvalidUser && err.message === AuthErrorMessages.UserAlreadyExists) { + this.authUserAtrErrors.email.wrongData = true; + } + } + this.spinnerService.hideSpinner(); + throw error; + })) + .subscribe(resp => { + this.spinnerService.hideSpinner(); + this.router.navigate(['/auth/login']); + }); + } + + confirmEMail(): void { + const id = this.route.snapshot.params['id']; + if (id) { + this.spinnerService.showSpinner(); + this.authService.confirmEMail(id) + .pipe(catchError(error => { + this.router.navigate(['/auth/login']); + this.spinnerService.hideSpinner(); + throw error; + })) + .subscribe(resp => { + this.spinnerService.hideSpinner(); + this.router.navigate(['/auth/login']); + }); + } + } +} diff --git a/kdb-web/src/app/modules/shared/guards/auth/auth.guard.spec.ts b/kdb-web/src/app/modules/shared/guards/auth/auth.guard.spec.ts new file mode 100644 index 0000000000..68889d22d9 --- /dev/null +++ b/kdb-web/src/app/modules/shared/guards/auth/auth.guard.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { AuthGuard } from './auth.guard'; + +describe('AuthGuard', () => { + let guard: AuthGuard; + + beforeEach(() => { + TestBed.configureTestingModule({}); + guard = TestBed.inject(AuthGuard); + }); + + it('should be created', () => { + expect(guard).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/modules/shared/guards/auth/auth.guard.ts b/kdb-web/src/app/modules/shared/guards/auth/auth.guard.ts new file mode 100644 index 0000000000..694dc644a1 --- /dev/null +++ b/kdb-web/src/app/modules/shared/guards/auth/auth.guard.ts @@ -0,0 +1,38 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; +import { catchError } from 'rxjs/operators'; +import { AuthService } from 'src/app/services/auth/auth.service'; +import { ThemeService } from 'src/app/services/theme/theme.service'; + +@Injectable({ + providedIn: 'root' +}) +export class AuthGuard implements CanActivate { + constructor( + private router: Router, + private authService: AuthService, + private themeService: ThemeService + ) { + } + + async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { + if (!this.authService.getToken().token) { + this.authService.logout(); + return false; + } + + if (!await this.authService.isUserLoggedInAsync()) { + this.authService.logout(); + return false; + } + + const role = route.data['role']; + if (role) { + if (!await this.authService.hasUserPermission(role)) { + this.router.navigate(['/dashboard']); + return false; + } + } + return true; + } +} diff --git a/kdb-web/src/app/modules/shared/pipes/auth-role.pipe.ts b/kdb-web/src/app/modules/shared/pipes/auth-role.pipe.ts new file mode 100644 index 0000000000..47b0e09273 --- /dev/null +++ b/kdb-web/src/app/modules/shared/pipes/auth-role.pipe.ts @@ -0,0 +1,13 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { AuthRoles } from 'src/app/models/auth/auth-roles.enum'; + +@Pipe({ + name: 'authRole' +}) +export class AuthRolePipe implements PipeTransform { + + transform(value: AuthRoles): string { + return AuthRoles[value].toString(); + } + +} diff --git a/kdb-web/src/app/modules/shared/pipes/bool.pipe.spec.ts b/kdb-web/src/app/modules/shared/pipes/bool.pipe.spec.ts new file mode 100644 index 0000000000..e78cbc018a --- /dev/null +++ b/kdb-web/src/app/modules/shared/pipes/bool.pipe.spec.ts @@ -0,0 +1,8 @@ +import { BoolPipe } from './bool.pipe'; + +describe('BoolPipe', () => { + it('create an instance', () => { + const pipe = new BoolPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/modules/shared/pipes/bool.pipe.ts b/kdb-web/src/app/modules/shared/pipes/bool.pipe.ts new file mode 100644 index 0000000000..fc2d54cfac --- /dev/null +++ b/kdb-web/src/app/modules/shared/pipes/bool.pipe.ts @@ -0,0 +1,21 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; + +@Pipe({ + name: 'bool' +}) +export class BoolPipe implements PipeTransform { + + constructor( + private translate: TranslateService + ) {} + + transform(value: boolean): string { + if (value === true) { + return this.translate.instant('common.bool_as_string.true'); + } + + return this.translate.instant('common.bool_as_string.false'); + } + +} diff --git a/kdb-web/src/app/modules/shared/pipes/ip-address.pipe.ts b/kdb-web/src/app/modules/shared/pipes/ip-address.pipe.ts new file mode 100644 index 0000000000..fb3f1176e1 --- /dev/null +++ b/kdb-web/src/app/modules/shared/pipes/ip-address.pipe.ts @@ -0,0 +1,27 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'ipAddress' +}) +export class IpAddressPipe implements PipeTransform { + + transform(ipAsArray: number[]): string { + let ipAsString = ""; + + if (ipAsArray.length != 4){ + throw new Error("Invalid IP") + } + + for (let i = 0; i < ipAsArray.length; i++) { + const byte = ipAsArray[i]; + if (i == ipAsArray.length - 1) { + ipAsString += `${byte}`; + } else { + ipAsString += `${byte}.`; + } + } + + return ipAsString; + } + +} diff --git a/kdb-web/src/app/modules/shared/shared.module.ts b/kdb-web/src/app/modules/shared/shared.module.ts new file mode 100644 index 0000000000..9a77a513cc --- /dev/null +++ b/kdb-web/src/app/modules/shared/shared.module.ts @@ -0,0 +1,71 @@ +import { CommonModule } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { TranslateModule } from '@ngx-translate/core'; +import { ButtonModule } from 'primeng/button'; +import { CheckboxModule } from 'primeng/checkbox'; +import { ConfirmDialogModule } from 'primeng/confirmdialog'; +import { DialogModule } from 'primeng/dialog'; +import { DropdownModule } from 'primeng/dropdown'; +import { DynamicDialogModule } from 'primeng/dynamicdialog'; +import { InputTextModule } from 'primeng/inputtext'; +import { MenuModule } from 'primeng/menu'; +import { PasswordModule } from 'primeng/password'; +import { ProgressSpinnerModule } from 'primeng/progressspinner'; +import { TableModule } from 'primeng/table'; +import { ToastModule } from 'primeng/toast'; +import { AuthRolePipe } from './pipes/auth-role.pipe'; +import { IpAddressPipe } from './pipes/ip-address.pipe'; +import { BoolPipe } from './pipes/bool.pipe'; + + + +@NgModule({ + declarations: [ + AuthRolePipe, + IpAddressPipe, + BoolPipe, + ], + imports: [ + CommonModule, + ButtonModule, + PasswordModule, + MenuModule, + DialogModule, + ProgressSpinnerModule, + HttpClientModule, + FormsModule, + ReactiveFormsModule, + ToastModule, + ConfirmDialogModule, + TableModule, + InputTextModule, + CheckboxModule, + DropdownModule, + TranslateModule, + DynamicDialogModule + ], + exports: [ + ButtonModule, + PasswordModule, + MenuModule, + DialogModule, + ProgressSpinnerModule, + HttpClientModule, + FormsModule, + ReactiveFormsModule, + ToastModule, + ConfirmDialogModule, + TableModule, + InputTextModule, + CheckboxModule, + DropdownModule, + TranslateModule, + DynamicDialogModule, + AuthRolePipe, + IpAddressPipe, + BoolPipe, + ] +}) +export class SharedModule { } diff --git a/kdb-web/src/app/modules/view/change-password/change-password-routing.module.ts b/kdb-web/src/app/modules/view/change-password/change-password-routing.module.ts new file mode 100644 index 0000000000..59da68449c --- /dev/null +++ b/kdb-web/src/app/modules/view/change-password/change-password-routing.module.ts @@ -0,0 +1,13 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { ChangePasswordComponent } from './components/change-password/change-password.component'; + +const routes: Routes = [ + {path: '', component:ChangePasswordComponent} +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class ChangePasswordRoutingModule { } diff --git a/kdb-web/src/app/modules/view/change-password/change-password.module.ts b/kdb-web/src/app/modules/view/change-password/change-password.module.ts new file mode 100644 index 0000000000..05d47342e9 --- /dev/null +++ b/kdb-web/src/app/modules/view/change-password/change-password.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { ChangePasswordRoutingModule } from './change-password-routing.module'; +import { ChangePasswordComponent } from './components/change-password/change-password.component'; +import { SharedModule } from '../../shared/shared.module'; + + +@NgModule({ + declarations: [ + ChangePasswordComponent + ], + imports: [ + CommonModule, + ChangePasswordRoutingModule, + SharedModule + ] +}) +export class ChangePasswordModule { } diff --git a/kdb-web/src/app/modules/view/change-password/components/change-password/change-password.component.html b/kdb-web/src/app/modules/view/change-password/components/change-password/change-password.component.html new file mode 100644 index 0000000000..0532651f16 --- /dev/null +++ b/kdb-web/src/app/modules/view/change-password/components/change-password/change-password.component.html @@ -0,0 +1,35 @@ +

+ {{'view.change-password.header' | translate}} +

+
+
+
+
+ +
+
{{'view.change-password.wrong_password' | translate}}
+
+
+ +
+ +
+ +
+ +
+
{{'view.change-password.passwords_do_not_match' | translate}}
+
+
+ + +
+
+
\ No newline at end of file diff --git a/kdb-web/src/app/modules/view/change-password/components/change-password/change-password.component.scss b/kdb-web/src/app/modules/view/change-password/components/change-password/change-password.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-web/src/app/modules/view/change-password/components/change-password/change-password.component.spec.ts b/kdb-web/src/app/modules/view/change-password/components/change-password/change-password.component.spec.ts new file mode 100644 index 0000000000..0776caea1d --- /dev/null +++ b/kdb-web/src/app/modules/view/change-password/components/change-password/change-password.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ChangePasswordComponent } from './change-password.component'; + +describe('ChangePasswordComponent', () => { + let component: ChangePasswordComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ChangePasswordComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(ChangePasswordComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/modules/view/change-password/components/change-password/change-password.component.ts b/kdb-web/src/app/modules/view/change-password/components/change-password/change-password.component.ts new file mode 100644 index 0000000000..29fb7f2f42 --- /dev/null +++ b/kdb-web/src/app/modules/view/change-password/components/change-password/change-password.component.ts @@ -0,0 +1,107 @@ +import { Component, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Router } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; +import { catchError } from 'rxjs/operators'; +import { AuthErrorMessages } from 'src/app/models/auth/auth-error-messages.enum'; +import { UpdateUserDTO } from 'src/app/models/auth/update-user.dto'; +import { ErrorDTO } from 'src/app/models/error/error-dto'; +import { ServiceErrorCode } from 'src/app/models/error/service-error-code.enum'; +import { AuthService } from 'src/app/services/auth/auth.service'; +import { SpinnerService } from 'src/app/services/spinner/spinner.service'; +import { ToastService } from 'src/app/services/toast/toast.service'; + +@Component({ + selector: 'app-change-password', + templateUrl: './change-password.component.html', + styleUrls: ['./change-password.component.scss'] +}) +export class ChangePasswordComponent implements OnInit { + + passwordForm!: FormGroup; + submitted = false; + ready = false; + errors = { + email: false, + repeatPassword: false, + oldPassword: false + }; + + constructor( + private authService: AuthService, + private formBuilder: FormBuilder, + private router: Router, + private spinnerService: SpinnerService, + private toastService: ToastService, + private translate: TranslateService + ) { } + + ngOnInit(): void { + this.initForms(); + } + + initForms(): void { + this.passwordForm = this.formBuilder.group({ + oldPassword: [null, [Validators.required, Validators.minLength(8)]], + password: [null, [Validators.required, Validators.minLength(8)]], + passwordRepeat: [null, [Validators.required, Validators.minLength(8)]] + }); + } + + resetErrorFlags(): void { + this.errors = { + email: false, + repeatPassword: false, + oldPassword: false + }; + } + + changePassword(): void { + this.submitted = true; + this.resetErrorFlags(); + + if (this.passwordForm.value.password !== this.passwordForm.value.passwordRepeat) { + this.errors.repeatPassword = true; + return; + } + this.spinnerService.showSpinner(); + + const decodedToken = this.authService.getDecodedToken(); + const changePasswordDTO: UpdateUserDTO = { + authUserDTO: { + firstName: null, + lastName: null, + password: this.passwordForm.value.oldPassword, + email: this.authService.getEMailFromDecodedToken(decodedToken) + }, + newAuthUserDTO: { + firstName: null, + lastName: null, + password: this.passwordForm.value.password, + email: this.authService.getEMailFromDecodedToken(decodedToken) + } + }; + + this.authService.updateUser(changePasswordDTO) + .pipe(catchError(error => { + if (error.error !== null) { + const err: ErrorDTO = error.error; + + if (err.errorCode === ServiceErrorCode.InvalidUser && err.message === AuthErrorMessages.WrongPassword) { + this.errors.oldPassword = true; + } + + error.error = null; + } + this.spinnerService.hideSpinner(); + this.toastService.error(this.translate.instant('view.change_password.message.error'), this.translate.instant('view.change_password.message.password_cannot_be_changed')); + throw error; + })) + .subscribe(resp => { + this.spinnerService.hideSpinner(); + this.toastService.success(this.translate.instant('view.change_password.message.change_password'), this.translate.instant('view.change_password.message.changed_password')); + this.router.navigate(["/dashboard"]); + }); + } + +} diff --git a/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.html b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.html new file mode 100644 index 0000000000..04e795ec56 --- /dev/null +++ b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.html @@ -0,0 +1,3 @@ +

dashboard works!

+ +
diff --git a/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.scss b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.spec.ts b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.spec.ts new file mode 100644 index 0000000000..5ec4ff8fc2 --- /dev/null +++ b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DashboardComponent } from './dashboard.component'; + +describe('DashboardComponent', () => { + let component: DashboardComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ DashboardComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(DashboardComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts new file mode 100644 index 0000000000..25d48a7ae5 --- /dev/null +++ b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts @@ -0,0 +1,14 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-dashboard', + templateUrl: './dashboard.component.html', + styleUrls: ['./dashboard.component.scss'] +}) +export class DashboardComponent implements OnInit { + + constructor() { } + + ngOnInit(): void {} + +} diff --git a/kdb-web/src/app/modules/view/dashboard/dashboard-routing.module.ts b/kdb-web/src/app/modules/view/dashboard/dashboard-routing.module.ts new file mode 100644 index 0000000000..27f772462c --- /dev/null +++ b/kdb-web/src/app/modules/view/dashboard/dashboard-routing.module.ts @@ -0,0 +1,13 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { DashboardComponent } from './components/dashboard/dashboard.component'; + +const routes: Routes = [ + {path: '', component: DashboardComponent} +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class DashboardRoutingModule { } diff --git a/kdb-web/src/app/modules/view/dashboard/dashboard.module.ts b/kdb-web/src/app/modules/view/dashboard/dashboard.module.ts new file mode 100644 index 0000000000..0b3abe11d6 --- /dev/null +++ b/kdb-web/src/app/modules/view/dashboard/dashboard.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { DashboardRoutingModule } from './dashboard-routing.module'; +import { DashboardComponent } from './components/dashboard/dashboard.component'; +import { SharedModule } from '../../shared/shared.module'; + + +@NgModule({ + declarations: [ + DashboardComponent + ], + imports: [ + CommonModule, + DashboardRoutingModule, + SharedModule + ] +}) +export class DashboardModule { } diff --git a/kdb-web/src/app/modules/view/user-settings/components/user-settings/user-settings.component.html b/kdb-web/src/app/modules/view/user-settings/components/user-settings/user-settings.component.html new file mode 100644 index 0000000000..716df73cef --- /dev/null +++ b/kdb-web/src/app/modules/view/user-settings/components/user-settings/user-settings.component.html @@ -0,0 +1,41 @@ +

+ {{'view.user_settings.header' | translate}} +

+
+
+
+
+
+ +
+ +
+ +
+
+ +
+ +
+
{{'view.user_settings.e_mail_already_exists' | translate}}
+
+
+ +
+ +
+
{{'view.user_settings.wrong_password' | translate}}
+
+
+ + +
+
+
\ No newline at end of file diff --git a/kdb-web/src/app/modules/view/user-settings/components/user-settings/user-settings.component.scss b/kdb-web/src/app/modules/view/user-settings/components/user-settings/user-settings.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-web/src/app/modules/view/user-settings/components/user-settings/user-settings.component.spec.ts b/kdb-web/src/app/modules/view/user-settings/components/user-settings/user-settings.component.spec.ts new file mode 100644 index 0000000000..4f52948188 --- /dev/null +++ b/kdb-web/src/app/modules/view/user-settings/components/user-settings/user-settings.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UserSettingsComponent } from './user-settings.component'; + +describe('UserSettingsComponent', () => { + let component: UserSettingsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ UserSettingsComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(UserSettingsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/modules/view/user-settings/components/user-settings/user-settings.component.ts b/kdb-web/src/app/modules/view/user-settings/components/user-settings/user-settings.component.ts new file mode 100644 index 0000000000..b4e8d6330e --- /dev/null +++ b/kdb-web/src/app/modules/view/user-settings/components/user-settings/user-settings.component.ts @@ -0,0 +1,151 @@ +import { Component, OnInit } from '@angular/core'; +import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { Router } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; +import { catchError } from 'rxjs/operators'; +import { AuthErrorMessages } from 'src/app/models/auth/auth-error-messages.enum'; +import { AuthUserDTO } from 'src/app/models/auth/auth-user.dto'; +import { UpdateUserDTO } from 'src/app/models/auth/update-user.dto'; +import { ErrorDTO } from 'src/app/models/error/error-dto'; +import { ServiceErrorCode } from 'src/app/models/error/service-error-code.enum'; +import { AuthService } from 'src/app/services/auth/auth.service'; +import { SpinnerService } from 'src/app/services/spinner/spinner.service'; +import { ThemeService } from 'src/app/services/theme/theme.service'; +import { ToastService } from 'src/app/services/toast/toast.service'; + +@Component({ + selector: 'app-user-settings', + templateUrl: './user-settings.component.html', + styleUrls: ['./user-settings.component.scss'] +}) +export class UserSettingsComponent implements OnInit { + settingsForm!: FormGroup<{ + firstName: FormControl, + lastName: FormControl, + email: FormControl, + password: FormControl + }>; + submitted = false; + ready = false; + errors = { + email: false, + password: false + }; + + authUser: AuthUserDTO | null = null; + + constructor( + private authService: AuthService, + private formBuilder: FormBuilder, + private router: Router, + private spinnerService: SpinnerService, + private toastService: ToastService, + private themeService: ThemeService, + private translaste: TranslateService + ) { } + + ngOnInit(): void { + this.initForms(); + this.load(); + } + + initForms(): void { + this.settingsForm = this.formBuilder.group({ + firstName: ['', [Validators.required]], + lastName: ['', [Validators.required]], + email: ['', [Validators.required, Validators.email]], + password: ['', [Validators.required, Validators.minLength(8)]] + }); + } + + resetErrorFlags(): void { + this.errors = { + email: false, + password: false + }; + } + + load(): void { + const token = this.authService.getDecodedToken(); + const mail = this.authService.getEMailFromDecodedToken(token); + if (!mail) { + return; + } + + this.authService.findUserByEMail(mail) + .pipe(catchError(err => { + this.toastService.error(this.translaste.instant('view.user_settings.message.user_not_found'), this.translaste.instant('view.user_settings.message.user_not_found_d')); + this.authService.logout(); + throw err; + })) + .subscribe(user => { + if (!user) { + this.toastService.error(this.translaste.instant('view.user_settings.message.user_not_found'), this.translaste.instant('view.user_settings.message.user_not_found_d')); + this.authService.logout(); + } + this.authUser = user; + this.settingsForm.controls.firstName.setValue(user.firstName); + this.settingsForm.controls.lastName.setValue(user.lastName); + this.settingsForm.controls.email.setValue(user.email); + }); + } + + saveSettings(): void { + if (!this.authUser) { + return; + } + + this.resetErrorFlags(); + this.submitted = true; + this.spinnerService.showSpinner(); + + this.authUser.password = this.settingsForm.value.password ?? null; + const updateUserDTO: UpdateUserDTO = { + authUserDTO: this.authUser, + newAuthUserDTO: { + firstName: this.settingsForm.value.firstName ?? null, + lastName: this.settingsForm.value.lastName ?? null, + email: this.settingsForm.value.email ?? null, + password: null + } + }; + + this.authService.updateUser(updateUserDTO) + .pipe(catchError(error => { + if (error.error !== null) { + const err: ErrorDTO = error.error; + + if (err.errorCode === ServiceErrorCode.InvalidUser && err.message === AuthErrorMessages.WrongPassword) { + this.errors.password = true; + } else if (err.errorCode === ServiceErrorCode.InvalidUser && err.message === AuthErrorMessages.UserAlreadyExists) { + this.errors.email = true; + } + } + this.spinnerService.hideSpinner(); + this.toastService.error(this.translaste.instant('view.user_settings.message.error'), this.translaste.instant('view.user_settings.message.could_not_change_settings')); + throw error; + })) + .subscribe(resp => { + updateUserDTO.newAuthUserDTO.password = updateUserDTO.authUserDTO.password; + this.authService.login(updateUserDTO.newAuthUserDTO) + .pipe(catchError(err => { + this.router.navigate(['/auth/login']); + throw err; + })) + .subscribe(token => { + this.spinnerService.hideSpinner(); + if (token) { + this.toastService.success(this.translaste.instant('view.user_settings.message.success'), this.translaste.instant('view.user_settings.message.changed_settings')); + this.authService.saveToken(token); + this.themeService.loadTheme(); + this.themeService.loadMenu(); + this.load(); + return true; + } + this.router.navigate(['/auth/login']); + return false; + }); + }); + } + +} diff --git a/kdb-web/src/app/modules/view/user-settings/user-settings-routing.module.ts b/kdb-web/src/app/modules/view/user-settings/user-settings-routing.module.ts new file mode 100644 index 0000000000..adbc0cd053 --- /dev/null +++ b/kdb-web/src/app/modules/view/user-settings/user-settings-routing.module.ts @@ -0,0 +1,13 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { UserSettingsComponent } from './components/user-settings/user-settings.component'; + +const routes: Routes = [ + { path: '', component: UserSettingsComponent } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class UserSettingsRoutingModule { } diff --git a/kdb-web/src/app/modules/view/user-settings/user-settings.module.ts b/kdb-web/src/app/modules/view/user-settings/user-settings.module.ts new file mode 100644 index 0000000000..722555da73 --- /dev/null +++ b/kdb-web/src/app/modules/view/user-settings/user-settings.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { UserSettingsRoutingModule } from './user-settings-routing.module'; +import { UserSettingsComponent } from './components/user-settings/user-settings.component'; +import { SharedModule } from '../../shared/shared.module'; + + +@NgModule({ + declarations: [ + UserSettingsComponent + ], + imports: [ + CommonModule, + UserSettingsRoutingModule, + SharedModule + ] +}) +export class UserSettingsModule { } diff --git a/kdb-web/src/app/services/auth/auth.service.spec.ts b/kdb-web/src/app/services/auth/auth.service.spec.ts new file mode 100644 index 0000000000..f1251cacf9 --- /dev/null +++ b/kdb-web/src/app/services/auth/auth.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { AuthService } from './auth.service'; + +describe('AuthService', () => { + let service: AuthService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(AuthService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/services/auth/auth.service.ts b/kdb-web/src/app/services/auth/auth.service.ts new file mode 100644 index 0000000000..f388e291f1 --- /dev/null +++ b/kdb-web/src/app/services/auth/auth.service.ts @@ -0,0 +1,243 @@ +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Router } from '@angular/router'; +import { JwtHelperService } from '@auth0/angular-jwt'; +import { Observable, Subscription } from 'rxjs'; +import { catchError } from 'rxjs/operators'; +import { AdminUpdateUserDTO } from 'src/app/models/auth/admin-update-user.dto'; +import { AuthRoles } from 'src/app/models/auth/auth-roles.enum'; +import { AuthUserDTO } from 'src/app/models/auth/auth-user.dto'; +import { EMailStringDTO } from 'src/app/models/auth/email-string.dto'; +import { ResetPasswordDTO } from 'src/app/models/auth/reset-password.dto'; +import { TokenDTO } from 'src/app/models/auth/token.dto'; +import { UpdateUserDTO } from 'src/app/models/auth/update-user.dto'; +import { AuthUserSelectCriterion } from 'src/app/models/selection/auth-user/auth-user-select-criterion.dto'; +import { GetFilteredAuthUsersResultDTO } from 'src/app/models/selection/auth-user/get-filtered-auth-users-result.dto'; +import { SettingsService } from '../settings/settings.service'; +import { SpinnerService } from '../spinner/spinner.service'; + +@Injectable({ + providedIn: 'root' +}) +export class AuthService { + + invalidLogin!: boolean; + isLoggedIn!: boolean; + + constructor( + private appsettings: SettingsService, + private http: HttpClient, + private router: Router, + private jwtHelper: JwtHelperService, + private spinnerService: SpinnerService + ) { + this.isUserLoggedInAsync(); + } + + /* data requests */ + getAllUsers(): Observable> { + return this.http.get>(`${this.appsettings.getApiURL()}/api/auth/users`, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } + getFilteredUsers(selectCriterions: AuthUserSelectCriterion): Observable { + return this.http.post(`${this.appsettings.getApiURL()}/api/auth/users/get/filtered`, selectCriterions, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } + + getUserByEMail(email: string): Observable { + return this.http.get(`${this.appsettings.getApiURL()}/api/auth/users/get/${email}`, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } + + findUserByEMail(email: string): Observable { + return this.http.get(`${this.appsettings.getApiURL()}/api/auth/users/find/${email}`, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } + + /* auth requsts */ + register(user: AuthUserDTO): Observable { + return this.http.post(`${this.appsettings.getApiURL()}/api/auth/register`, user, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } + + confirmEMail(id: string): Observable { + return this.http.post(`${this.appsettings.getApiURL()}/api/auth/register/${id}`, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } + + login(user: AuthUserDTO): Observable { + return this.http.post(`${this.appsettings.getApiURL()}/api/auth/login`, user, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } + + forgotPassword(email: string): Observable { + const emailJson = JSON.stringify(email); + return this.http.post(`${this.appsettings.getApiURL()}/api/auth/forgot-password`, emailJson, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } + + getEMailFromforgotPasswordId(id: string): Observable { + const idJson = JSON.stringify(id); + return this.http.post(`${this.appsettings.getApiURL()}/api/auth/confirm-forgot-password`, idJson, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } + + resetPassword(resetPasswordDTO: ResetPasswordDTO): Observable { + return this.http.post(`${this.appsettings.getApiURL()}/api/auth/reset-password`, resetPasswordDTO, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } + + updateUser(updateUserDTO: UpdateUserDTO): Observable { + return this.http.post(`${this.appsettings.getApiURL()}/api/auth/update-user`, updateUserDTO, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } + + updateUserAsAdmin(updateUserDTO: AdminUpdateUserDTO): Observable { + return this.http.post(`${this.appsettings.getApiURL()}/api/auth/update-user-as-admin`, updateUserDTO, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } + + refresh(token: TokenDTO): Observable { + return this.http.post(`${this.appsettings.getApiURL()}/api/auth/refresh`, token, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } + + logout(): Subscription | null { + const token = this.getToken(); + this.isLoggedIn = false; + localStorage.removeItem('jwt'); + localStorage.removeItem('rjwt'); + this.router.navigate(['/auth/login']); + + if (token && token.token && token.refreshToken) { + return this.http.post(`${this.appsettings.getApiURL()}/api/auth/revoke`, token, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }).pipe(catchError((error: any) => { + error.error = null; + throw error; + })).subscribe(); + } + + return null + } + + deleteUserByMail(mail: string) { + return this.http.post(`${this.appsettings.getApiURL()}/api/auth/delete-user-by-mail/${mail}`, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } + + /* utils */ + saveToken(token: TokenDTO): void { + localStorage.setItem('jwt', token.token); + localStorage.setItem('rjwt', token.refreshToken); + if (this.router.url.startsWith('/auth')) { + this.router.navigate(['/dashboard']); + } + } + + getToken(): TokenDTO { + return { + token: localStorage.getItem('jwt') ?? '', + refreshToken: localStorage.getItem('rjwt') ?? '' + }; + } + + getDecodedToken(): { [key: string]: any } { + return this.jwtHelper.decodeToken(this.getToken().token); + } + + async isUserLoggedInAsync(): Promise { + this.isLoggedIn = await this._isUserLoggedInAsync(); + return this.isLoggedIn; + } + + private async _isUserLoggedInAsync(): Promise { + const token = this.getToken(); + if (!token || !token.refreshToken) { + this.isLoggedIn = false; + return false; + } + + if (token.token && !this.jwtHelper.isTokenExpired(token.token)) { + this.isLoggedIn = true; + return true; + } + + if (this.isLoggedIn !== false) { + this.spinnerService.showSpinner(); + const resfreshedToken = await this.refresh(token) + .pipe(catchError((err: Error) => { + this.logout(); + this.spinnerService.hideSpinner(); + throw err; + })) + .toPromise(); + this.spinnerService.hideSpinner(); + if (resfreshedToken) { + this.saveToken(resfreshedToken); + return true; + } + } + this.isLoggedIn = false; + return false; + } + + async hasUserPermission(role: AuthRoles): Promise { + if (!role || !await this.isUserLoggedInAsync()) { + return false; + } + const token = this.getDecodedToken(); + return AuthRoles[token['role']] === AuthRoles[role]; + } + + getEMailFromDecodedToken(token: { [key: string]: any }): string | null { + if (!token) { + return null; + } + return token['email']; + } +} diff --git a/kdb-web/src/app/services/confirmation-dialog/confirmation-dialog.service.spec.ts b/kdb-web/src/app/services/confirmation-dialog/confirmation-dialog.service.spec.ts new file mode 100644 index 0000000000..79f95ddb76 --- /dev/null +++ b/kdb-web/src/app/services/confirmation-dialog/confirmation-dialog.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { ConfirmationDialogService } from './confirmation-dialog.service'; + +describe('ConfirmationDialogService', () => { + let service: ConfirmationDialogService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(ConfirmationDialogService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/services/confirmation-dialog/confirmation-dialog.service.ts b/kdb-web/src/app/services/confirmation-dialog/confirmation-dialog.service.ts new file mode 100644 index 0000000000..c50bb19ccd --- /dev/null +++ b/kdb-web/src/app/services/confirmation-dialog/confirmation-dialog.service.ts @@ -0,0 +1,53 @@ +import { Injectable } from '@angular/core'; +import { ConfirmationService } from 'primeng/api'; +import { ConfirmationDialog } from 'src/app/models/utils/confirmation-dialog'; + +@Injectable({ + providedIn: 'root' +}) +export class ConfirmationDialogService { + + constructor( + private confirmationService: ConfirmationService + ) { } + + errorDialog(header: string, message: string) { + this.confirmationService.confirm({ + key: 'errorConfirmationDialog', + header: header, + message: message + }); + } + + confirmDialog(header: string, message: string, accept?: () => void, reject?: () => void) { + let options: ConfirmationDialog = { + key: 'confirmConfirmationDialog', + header: header, + message: message + }; + + if (accept) { + options.accept = accept; + } + + if (reject) { + options.reject = reject; + } + + this.confirmationService.confirm(options); + } + + warningDialog(header: string, message: string, accept?: () => void) { + let options: ConfirmationDialog = { + key: 'warningConfirmationDialog', + header: header, + message: message + }; + + if (accept) { + options.accept = accept; + } + + this.confirmationService.confirm(options); + } +} diff --git a/kdb-web/src/app/services/data/data.service.spec.ts b/kdb-web/src/app/services/data/data.service.spec.ts new file mode 100644 index 0000000000..38e8d9ec63 --- /dev/null +++ b/kdb-web/src/app/services/data/data.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { DataService } from './data.service'; + +describe('DataService', () => { + let service: DataService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(DataService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/services/data/data.service.ts b/kdb-web/src/app/services/data/data.service.ts new file mode 100644 index 0000000000..36cccbb5a4 --- /dev/null +++ b/kdb-web/src/app/services/data/data.service.ts @@ -0,0 +1,14 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { SettingsService } from '../settings/settings.service'; + +@Injectable({ + providedIn: 'root' +}) +export class DataService { + + constructor( + private appsettings: SettingsService, + private http: HttpClient, + ) { } +} diff --git a/kdb-web/src/app/services/error-handler/error-handler.service.spec.ts b/kdb-web/src/app/services/error-handler/error-handler.service.spec.ts new file mode 100644 index 0000000000..d74faff8a3 --- /dev/null +++ b/kdb-web/src/app/services/error-handler/error-handler.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { ErrorHandlerService } from './error-handler.service'; + +describe('ErrorHandlerService', () => { + let service: ErrorHandlerService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(ErrorHandlerService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/services/error-handler/error-handler.service.ts b/kdb-web/src/app/services/error-handler/error-handler.service.ts new file mode 100644 index 0000000000..ac8bb59afb --- /dev/null +++ b/kdb-web/src/app/services/error-handler/error-handler.service.ts @@ -0,0 +1,34 @@ +import { HttpErrorResponse } from '@angular/common/http'; +import { ErrorHandler, Injectable, Injector } from '@angular/core'; +import { Observable, throwError } from 'rxjs'; +import { ErrorDTO } from 'src/app/models/error/error-dto'; +import { ToastService } from '../toast/toast.service'; + +@Injectable() +export class ErrorHandlerService implements ErrorHandler { + + constructor( + private injector: Injector + ) { } + + handleError(error: HttpErrorResponse): Observable { + if (error && error.error) { + let message = 'Unbekannter Fehler'; + let header = 'Fehler'; + const errorDto: ErrorDTO = error.error; + + if (errorDto.errorCode !== undefined) { + header = 'Fehlercode: ' + errorDto.errorCode; + } + + if (errorDto.message) { + message = errorDto.message; + } else if (error.message) { + message = error.message; + } + + this.injector.get(ToastService).error(header, message); + } + return throwError(error); + } +} diff --git a/kdb-web/src/app/services/gui/gui.service.spec.ts b/kdb-web/src/app/services/gui/gui.service.spec.ts new file mode 100644 index 0000000000..c4fc503555 --- /dev/null +++ b/kdb-web/src/app/services/gui/gui.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { GuiService } from './gui.service'; + +describe('GuiService', () => { + let service: GuiService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(GuiService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/services/gui/gui.service.ts b/kdb-web/src/app/services/gui/gui.service.ts new file mode 100644 index 0000000000..20364e44c4 --- /dev/null +++ b/kdb-web/src/app/services/gui/gui.service.ts @@ -0,0 +1,41 @@ +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable, Subscribable } from 'rxjs'; +import { SettingsDTO } from 'src/app/models/config/settings.dto'; +import { SoftwareVersionDTO } from 'src/app/models/config/software-version.dto'; +import { SettingsService } from '../settings/settings.service'; + +@Injectable({ + providedIn: 'root' +}) +export class GuiService { + + constructor( + private appsettings: SettingsService, + private http: HttpClient, + ) { } + + getApiVersion(): Observable { + return this.http.get(`${this.appsettings.getApiURL()}/api/gui/api-version`, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } + + getSettings(): Observable { + return this.http.get(`${this.appsettings.getApiURL()}/api/gui/settings`, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } + + sendTestMail(mail: string): Observable { + return this.http.post(`${this.appsettings.getApiURL()}/api/gui/send-test-mail/${mail}`, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } +} diff --git a/kdb-web/src/app/services/settings/settings.service.spec.ts b/kdb-web/src/app/services/settings/settings.service.spec.ts new file mode 100644 index 0000000000..359cb6b7ae --- /dev/null +++ b/kdb-web/src/app/services/settings/settings.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { SettingsService } from './settings.service'; + +describe('SettingsService', () => { + let service: SettingsService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(SettingsService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/services/settings/settings.service.ts b/kdb-web/src/app/services/settings/settings.service.ts new file mode 100644 index 0000000000..17c292d1bd --- /dev/null +++ b/kdb-web/src/app/services/settings/settings.service.ts @@ -0,0 +1,62 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { throwError } from 'rxjs'; +import { catchError } from 'rxjs/operators'; +import { Appsettings } from 'src/app/models/config/appsettings'; +import { SoftwareVersion } from 'src/app/models/config/software-version'; +import { Theme } from 'src/app/models/view/theme'; +import { Themes } from 'src/app/models/view/themes.enum'; + +@Injectable({ + providedIn: 'root' +}) +export class SettingsService { + appsettings!: Appsettings; + + constructor( + private http: HttpClient + ) { } + + loadSettings(): Promise { + return new Promise((resolve, reject) => { + this.http.get('../../assets/config.json') + .pipe(catchError(error => { + reject(error); + return throwError(error); + })).subscribe(settings => { + this.appsettings = settings; + resolve(settings); + }); + }); + } + + public getApiURL(): string { + if (!this.appsettings || !this.appsettings.ApiURL) { + console.error('ApiURL is not set!'); + return ''; + } + return this.appsettings.ApiURL; + } + + public getWebVersion(): SoftwareVersion | null { + if (!this.appsettings || !this.appsettings.WebVersion) { + console.error('WebVersion is not set!'); + return null; + } + const webVersion = new SoftwareVersion( + this.appsettings.WebVersion.Major, + this.appsettings.WebVersion.Minor, + this.appsettings.WebVersion.Micro + ); + return webVersion; + } + + public getThemes(): Theme[] | null { + if (!this.appsettings || !this.appsettings.Themes) { + console.error('Themes is not set!'); + return null; + } + return this.appsettings.Themes; + } +} + diff --git a/kdb-web/src/app/services/spinner/spinner.service.spec.ts b/kdb-web/src/app/services/spinner/spinner.service.spec.ts new file mode 100644 index 0000000000..222e634a83 --- /dev/null +++ b/kdb-web/src/app/services/spinner/spinner.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { SpinnerService } from './spinner.service'; + +describe('SpinnerService', () => { + let service: SpinnerService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(SpinnerService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/services/spinner/spinner.service.ts b/kdb-web/src/app/services/spinner/spinner.service.ts new file mode 100644 index 0000000000..0d3aab972e --- /dev/null +++ b/kdb-web/src/app/services/spinner/spinner.service.ts @@ -0,0 +1,22 @@ +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class SpinnerService { + + showSpinnerState = false; + constructor() { } + + showSpinner() { + this.showSpinnerState = true; + } + + hideSpinner() { + this.showSpinnerState = false; + } + + toggleSpinner() { + this.showSpinnerState = !this.showSpinnerState; + } +} diff --git a/kdb-web/src/app/services/theme/theme.service.spec.ts b/kdb-web/src/app/services/theme/theme.service.spec.ts new file mode 100644 index 0000000000..1c2957ba89 --- /dev/null +++ b/kdb-web/src/app/services/theme/theme.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { ThemeService } from './theme.service'; + +describe('ThemeService', () => { + let service: ThemeService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(ThemeService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/services/theme/theme.service.ts b/kdb-web/src/app/services/theme/theme.service.ts new file mode 100644 index 0000000000..47537679db --- /dev/null +++ b/kdb-web/src/app/services/theme/theme.service.ts @@ -0,0 +1,98 @@ +import { Injectable } from '@angular/core'; +import { Themes } from 'src/app/models/view/themes.enum'; +import { AuthService } from '../auth/auth.service'; + +@Injectable({ + providedIn: 'root' +}) +export class ThemeService { + + themeName: string | null; + + sidebarWidth = '150px'; + isSidebarOpen = false; + hasLangChanged = false; + + constructor( + private authService: AuthService + ) { + this.loadTheme(); + this.loadMenu(); + this.themeName = null; + } + + loadTheme(): void { + const token = this.authService.getDecodedToken(); + const mail = this.authService.getEMailFromDecodedToken(token); + + let defaultThemeName = localStorage.getItem(`default_themeName`); + if (!defaultThemeName || defaultThemeName != Themes.Default) { + defaultThemeName = Themes.Default; + } + + if (!mail) { + this.setTheme(defaultThemeName); + return; + } + + let userThemeName = localStorage.getItem(`${mail}_themeName`); + if (!userThemeName) { + this.setTheme(defaultThemeName); + return; + } + this.setTheme(userThemeName); + } + + setTheme(name: string): void { + this.authService.isUserLoggedInAsync().then(result => { + if (!result) { + localStorage.setItem(`default_themeName`, Themes.Default); + this.themeName = Themes.Default; + } + + const token = this.authService.getDecodedToken(); + const mail = this.authService.getEMailFromDecodedToken(token); + if (mail) { + localStorage.setItem(`${mail}_themeName`, name); + } + localStorage.setItem(`default_themeName`, name); + this.themeName = name; + }); + } + + loadMenu() { + const token = this.authService.getDecodedToken(); + const mail = this.authService.getEMailFromDecodedToken(token); + + if (!mail) { + this.setSideWidth(true); + return; + } + + let isMenuOpen = true; + let isMenuOpenStr = localStorage.getItem(`${mail}_isMenuOpen`); + if (isMenuOpenStr) { + isMenuOpen = Boolean(isMenuOpenStr); + } + + this.setIsMenuOpen(isMenuOpen); + } + + setIsMenuOpen(isMenuOpen: boolean) { + const token = this.authService.getDecodedToken(); + const mail = this.authService.getEMailFromDecodedToken(token); + + if (!mail) { + this.setSideWidth(true); + return; + } + + localStorage.setItem(`${mail}_isMenuOpen`, isMenuOpen + ""); + this.setSideWidth(isMenuOpen); + } + + setSideWidth($event: any): void { + this.sidebarWidth = $event ? '150px' : '50px'; + this.isSidebarOpen = $event; + } +} diff --git a/kdb-web/src/app/services/toast/toast.service.spec.ts b/kdb-web/src/app/services/toast/toast.service.spec.ts new file mode 100644 index 0000000000..e0413db848 --- /dev/null +++ b/kdb-web/src/app/services/toast/toast.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { ToastService } from './toast.service'; + +describe('ToastService', () => { + let service: ToastService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(ToastService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/services/toast/toast.service.ts b/kdb-web/src/app/services/toast/toast.service.ts new file mode 100644 index 0000000000..035a557927 --- /dev/null +++ b/kdb-web/src/app/services/toast/toast.service.ts @@ -0,0 +1,40 @@ +import { Injectable } from '@angular/core'; +import { MessageService } from 'primeng/api'; +import { ToastOptions } from 'src/app/models/utils/toast-options'; + +@Injectable({ + providedIn: 'root' +}) +export class ToastService { + + constructor( + private messageService: MessageService + ) { } + + private toast(type: string, summary: string, detail: string, options?: ToastOptions) { + this.messageService.add({ + severity: type, + summary: summary, + detail: detail, + life: options?.life, + sticky: options?.sticky, + closable: options?.closable + }); + } + + success(summary: string, detail: string, options?: ToastOptions) { + this.toast('success', summary, detail, options); + } + + info(summary: string, detail: string, options?: ToastOptions) { + this.toast('info', summary, detail, options); + } + + warn(summary: string, detail: string, options?: ToastOptions) { + this.toast('warn', summary, detail, options); + } + + error(summary: string, detail: string, options?: ToastOptions) { + this.toast('error', summary, detail, options); + } +} diff --git a/kdb-web/src/assets/.gitkeep b/kdb-web/src/assets/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-web/src/assets/config.json b/kdb-web/src/assets/config.json new file mode 100644 index 0000000000..905b2d2f3c --- /dev/null +++ b/kdb-web/src/assets/config.json @@ -0,0 +1,26 @@ +{ + "ApiURL": "http://localhost:5000", + "WebVersion": { + "Major": "0", + "Minor": "3", + "Micro": "0" + }, + "Themes": [ + { + "Label": "Blue light", + "Name": "default-light-theme" + }, + { + "Label": "Blue dark", + "Name": "default-dark-theme" + }, + { + "Label": "Orange light", + "Name": "sh-edraft-light-theme" + }, + { + "Label": "Orange dark", + "Name": "sh-edraft-dark-theme" + } + ] +} \ No newline at end of file diff --git a/kdb-web/src/assets/i18n/de.json b/kdb-web/src/assets/i18n/de.json new file mode 100644 index 0000000000..b51660d4e1 --- /dev/null +++ b/kdb-web/src/assets/i18n/de.json @@ -0,0 +1,258 @@ +{ + "header": { + "change_password": "Passwort ändern", + "settings": "Einstellungen", + "logout": "Ausloggen", + "header": "Krümmelmonster WI" + }, + "sidebar": { + "dashboard": "Dashboard", + "domain_list": "Domänen", + "host_list": "Rechner", + "user_list": "Benutzer", + "login_list": "Logins", + "config": "Konfiguration", + "auth_user_list": "Benutzer" + }, + "admin": { + "settings": { + "header": "Konfiguration", + "website": { + "header": "Webseite", + "frontend_version": "Webseite Version", + "backend_version": "Server Version", + "config_path": "Konfigurations-Dateipfad", + "frontend_base_url": "Webseite Basis-URL", + "backend_base_url": "Server Basis-URL", + "token_expire_time": "Token Ablaufzeit", + "refresh_token_expire_time": "Refresh Token Ablaufzeit" + }, + "e_mail": { + "header": "E-Mail", + "user": "Benutzer", + "host": "Host", + "port": "Port", + "transceiver": "Absender", + "e_mail_address": "E-Mail Adresse", + "e_mail": "E-Mail", + "send_e_mail": "E-Mail senden" + }, + "message": { + "error": "Fehler", + "could_not_send_mail": "E-Mail konte nicht gesendet werden!", + "connection_failed": "Verbindung fehlgeschlagen", + "connection_to_mail_failed": "Die Verbindung zum Mailserver konnte nicht hergestellt werden!", + "mail_login_failed": "Die Anmeldung am Mailserver ist fehlgeschlagen!", + "send_failed": "Senden fehlgeschlagen", + "test_mail_not_send": "Die Test E-Mail konnte nicht gesendet werden!", + "success": "Erfolg", + "send_mail": "E-Mail wurde erfolgreich gesendet" + } + }, + "auth_users": { + "header": "Benutzer", + "of": "von", + "add": "Hinzufügen", + "reset_filters": "Filter zurücksetzen", + "users": "Benutzer", + "headers": { + "users": "Benutzer", + "first_name": "Vorname", + "last_name": "Nachname", + "e_mail": "E-Mail", + "active": "Aktiv", + "role": "Rolle", + "password": "Passwort", + "actions": "Aktionen" + }, + "no_entries_found": "Keine Einträge gefunden", + "message": { + "invalid_email": "Ungültige E-Mail", + "invalid_email_d": "Die E-Mail {{eMail}} ist nicht gültig!", + "user_already_exists": "Benutzer existiert bereits", + "user_already_exists_d": "Der Benutzer {{eMail}} existiert bereits!", + "user_added": "Benutzer hinzugefügt", + "user_added_d": "Benutzer {{eMail}} erfolgreich hinzugefügt", + "user_change_failed": "Benutzer änderung fehlgeschlagen", + "user_change_failed_d": "Benutzer {{eMail}} konnte nicht geändert werden!", + "user_changed": "Benutzer geändert", + "user_changed_d": "Benutzer {{eMail}} erfolgreich geändert", + "cannot_delete_user": "Benutzer kann nicht gelöscht werden", + "logon_with_another_user": "Loggen Sie sich mit einem anderen Benutzer ein, um diesen Benutzer zu löschen!", + "user_delete": "Benutzer löschen", + "user_delete_q": "Sind Sie sich sicher, dass Sie {{eMail}} löschen möchten?", + "user_deleted": "Benutzer gelöscht", + "user_deleted_d": "Benutzer {{eMail}} erfolgreich gelöscht" + } + } + }, + "auth": { + "header": "Krümmelmonster WI", + "login": {}, + "register": {}, + "forgot_password": { + "e_mail": "E-Mail", + "send_confirmation_url": "Falls ein Benutzer mit der E-Mail gefunden wurde, wurde Betstätigungslink versendet", + "reset_password": "Passwort zurücksetzen", + "login": "Anmelden", + "register": "Registrieren", + "repeat_password": "Passwort wiederholen", + "passwords_do_not_match": "Die Passwörter stimmen nicht überein", + "password": "Passwort", + "message": { + "reset_password": "Passwort zurückgesetzt", + "reset_password_d": "Dein Passwort wurde zurückgesetzt" + } + } + }, + "view": { + "dashboard": {}, + "user-list": {}, + "change-password": { + "header": "Passwort ändern", + "wrong_password": "Falsches Passwort", + "passwords_do_not_match": "Die Passwörter stimmen nicht überein", + "password": "Passwort", + "active_password": "Aktuelles Passwort", + "new_password": "Neues Passwort", + "repeat_new_password": "Neues Passwort wiederholen", + "save": "Speichern", + "message": { + "error": "Fehler", + "password_cannot_be_changed": "Dein Passwort konnte nicht geändert werden!", + "change_password": "Passwort geändert", + "changed_password": "Dein Passwort wurde geändert" + } + }, + "user_settings": { + "header": "Einstellungen", + "first_name": "Vorname", + "last_name": "Nachname", + "e_mail": "E-Mail", + "password": "Passwort", + "e_mail_already_exists": "Die E-Mail wurde bereits vergeben", + "wrong_password": "Falsches Passwort", + "save": "Speichern", + "message": { + "user_not_found": "Benutzer nicht gefunden", + "user_not_found_d": "Der Benutzer konnte nicht gefunden werden!", + "error": "Fehler", + "could_not_change_settings": "Die Einstellungen konnten nicht geändert werden!", + "changed_settings": "Die Einstellungen wurden geändert", + "success": "Erfolg" + } + } + }, + "footer": { + "imprint": "Impressum", + "backend": "Webseite", + "frontend": "API" + }, + "dialog": { + "confirm": "Bestätigen", + "abort": "Abbrechen" + }, + "general": { + "days": "Tage", + "minutes": "Minuten" + }, + "common": { + "bool_as_string": { + "true": "Ja", + "false": "Nein" + }, + "error": "Fehler", + "404": "404 - Der Eintrag konnte nicht gefunden werden" + }, + "primeng": { + "startsWith": "Startet mit", + "contains": "Enthält", + "notContains": "Enthält nicht", + "endsWith": "Ended mit", + "equals": "Gleich", + "notEquals": "Nicht gleich", + "noFilter": "Kein Filter", + "lt": "Weniger als", + "lte": "Weniger als oder gleich", + "gt": "Größer als", + "gte": "Größer als doer gleich", + "is": "Ist", + "isNot": "Ist nicht", + "before": "Vorher", + "after": "Nachher", + "clear": "Zurücksetzen", + "apply": "Anwenden", + "matchAll": "Passend zu allem", + "matchAny": "Passend zu jedem", + "addRule": "Regel hinzufügen", + "removeRule": "Regel entfernen", + "accept": "Ja", + "reject": "Nein", + "choose": "Wählen", + "upload": "Hochladen", + "cancel": "Abbrechen", + "dayNames": [ + "Sonntag", + "Montag", + "Dienstag", + "Mittwoch", + "Donnerstag", + "Freitag", + "Samstag" + ], + "dayNamesShort": [ + "Son", + "Mon", + "Die", + "Mit", + "Don", + "Fre", + "Sam" + ], + "dayNamesMin": [ + "So", + "Mo", + "Di", + "Mi", + "Do", + "Fr", + "Sa" + ], + "monthNames": [ + "Januar", + "Februar", + "März", + "April", + "Mai", + "Juni", + "Juli", + "August", + "September", + "Oktober", + "November", + "Dezember" + ], + "monthNamesShort": [ + "Jan", + "Feb", + "Mär", + "Apr", + "Mai", + "Jun", + "Jul", + "Aug", + "Sep", + "Okt", + "Nov", + "Dez" + ], + "today": "Heute", + "weekHeader": "Wk", + "weak": "Woche", + "medium": "Mittel", + "strong": "Stark", + "passwordPrompt": "Passwort eingeben", + "emptyMessage": "Keine Ergebnisse gefunden", + "emptyFilterMessage": "Keine Ergebnisse gefunden" + } +} \ No newline at end of file diff --git a/kdb-web/src/assets/i18n/en.json b/kdb-web/src/assets/i18n/en.json new file mode 100644 index 0000000000..28a8c47b12 --- /dev/null +++ b/kdb-web/src/assets/i18n/en.json @@ -0,0 +1,322 @@ +{ + "header": { + "change_password": "Change Password", + "settings": "Settings", + "logout": "Logout" + }, + "sidebar": { + "dashboard": "Dashboard", + "domain_list": "Domains", + "host_list": "Hosts", + "user_list": "Users", + "login_list": "Logins", + "config": "Configuration", + "auth_user_list": "User" + }, + "admin": { + "settings": { + "header": "Configuration", + "website": { + "header": "Website", + "frontend_version": "Website version", + "backend_version": "Server version", + "config_path": "Configuration-Path", + "frontend_base_url": "Website Base-URL", + "backend_base_url": "Server Base-URL", + "token_expire_time": "Token expire time", + "refresh_token_expire_time": "Refresh Token expire time" + }, + "e_mail": { + "header": "E-Mail", + "user": "User", + "host": "Host", + "port": "Port", + "transceiver": "Sender", + "e_mail_address": "E-Mail address", + "e_mail": "E-Mail", + "send_e_mail": "Send E-Mail" + }, + "message": { + "error": "Error", + "could_not_send_mail": "E-mail could not be sent!", + "connection_failed": "Connection Failed", + "connection_to_mail_failed": "The connection to the mail server could not be established!", + "mail_login_failed": "The registration at the mail server failed!", + "send_failed": "Sending failed", + "test_mail_not_send": "The test email could not be sent!", + "success": "Success", + "send_mail": "Email was sent successfully" + } + }, + "auth_users": { + "header": "User", + "of": "of", + "add": "Add", + "reset_filters": "Reset filters", + "users": "User", + "headers": { + "users": "User", + "first_name": "Forename", + "last_name": "Surname", + "e_mail": "E-Mail", + "active": "Active", + "role": "Role", + "password": "Password", + "actions": "Actions" + }, + "no_entries_found": "No entries found", + "message": { + "invalid_email": "Invalid E-Mail", + "invalid_email_d": "The e-mail {{eMail}} is not valid!", + "user_already_exists": "User already exists", + "user_already_exists_d": "The user {{eMail}} already exists!", + "user_added": "User added", + "user_added_d": "User {{eMail}} successfully added", + "user_change_failed": "User change failed", + "user_change_failed_d": "User {{eMail}} could not be changed!", + "user_changed": "User changed", + "user_changed_d": "User {{eMail}} changed successfully", + "cannot_delete_user": "User cannot be deleted", + "logon_with_another_user": "Log in with another user to delete this user!", + "user_delete": "Delete user", + "user_delete_q": "Are you sure you want to delete {{eMail}}?", + "user_deleted": "User deleted", + "user_deleted_d": "User {{eMail}} successfully deleted" + } + } + }, + "auth": { + "header": "Login counter", + "login": { + "e_mail": "E-Mail", + "password": "Password", + "login": "Login", + "register": "Register", + "forgot_password": "Forgot password", + "e_mail_required": "E-Mail required", + "user_not_found": "User not found", + "e_mail_not_confirmed": "Email was not confirmed", + "password_required": "Passwort required", + "wrong_password": "Wrong password" + }, + "register": { + "first_name": "Forename", + "last_name": "Surname", + "e_mail": "E-Mail", + "repeat_e_mail": "Repeat E-mail", + "password": "Password", + "repeat_password": "Repeat password", + "register": "Register", + "login": "Login", + "user_already_exists": "User already exists", + "passwords_not_match": "The passwords do not match", + "e_mails_not_match": "The emails do not match", + "first_name_required": "Forename required", + "last_name_required": "Surname required", + "e_mail_required": "E-Mail required", + "password_required": "Passwort required", + "first_name_invalid": "Forename invalid", + "last_name_invalid": "Surname invalid" + }, + "forgot_password": { + "e_mail": "E-Mail", + "send_confirmation_url": "If a user was found with the email, a confirmation link was sent", + "reset_password": "Reset password", + "login": "Login", + "register": "Register", + "repeat_password": "Repeat password", + "passwords_do_not_match": "The passwords do not match", + "password": "Password", + "message": { + "reset_password": "Password reset", + "reset_password_d": "Your password has been reset" + } + } + }, + "view": { + "dashboard": {}, + "user-list": {}, + "change-password": { + "header": "Change Password", + "wrong_password": "Wrong password", + "passwords_do_not_match": "The passwords do not match", + "password": "Password", + "active_password": "Current Password", + "new_password": "New password", + "repeat_new_password": "Repeat new password", + "save": "Save", + "message": { + "error": "Error", + "password_cannot_be_changed": "Your password could not be changed!", + "change_password": "Changed password", + "changed_password": "Your password has been changed" + } + }, + "user_settings": { + "header": "Settings", + "first_name": "Forename", + "last_name": "Surname", + "e_mail": "E-Mail", + "password": "Password", + "e_mail_already_exists": "The email has already been taken", + "wrong_password": "Wrong password", + "save": "Save", + "message": { + "user_not_found": "User not found", + "user_not_found_d": "The user could not be found!", + "error": "Error", + "could_not_change_settings": "The settings could not be changed!", + "changed_settings": "Settings changed", + "success": "Success" + } + } + }, + "footer": { + "imprint": "Imprint", + "backend": "Website", + "frontend": "API" + }, + "dialog": { + "confirm": "Confirm", + "abort": "Abort" + }, + "general": { + "days": "Days", + "minutes": "Minutes" + }, + "login_models": { + "domain": { + "header": "Domain", + "name": "Name", + "users": "User", + "hosts": "Hosts", + "notify_when_login": "Notification after login", + "not_found": "Domain not found!" + }, + "host": { + "header": "Host", + "name": "Name", + "ip_address": "IP Address", + "users": "User", + "domain": "Domain", + "os": "Operating system", + "notify_when_login": "Notification after login", + "not_found": "Host not found!" + }, + "user": { + "header": "User", + "name": "Name", + "host": "Host", + "domain": "Domain", + "notify_when_login": "Notification after login", + "not_found": "User not found!" + }, + "login": { + "header": "Login", + "time": "Time", + "user": "User", + "host": "Host", + "notify_when_login": "Notification after login", + "not_found": "Login not found!" + } + }, + "common": { + "bool_as_string": { + "true": "Yes", + "false": "No" + }, + "error": "Error", + "404": "404 - Entry not found!" + }, + "primeng": { + "startsWith": "Starts with", + "contains": "Contains", + "notContains": "Not contains", + "endsWith": "Ends with", + "equals": "Equals", + "notEquals": "Not equals", + "noFilter": "No Filter", + "lt": "Less than", + "lte": "Less than or equal to", + "gt": "Greater than", + "gte": "Great then or equals", + "is": "Is", + "isNot": "Is not", + "before": "Before", + "after": "After", + "clear": "Clear", + "apply": "Apply", + "matchAll": "Match All", + "matchAny": "Match Any", + "addRule": "Add Rule", + "removeRule": "Remove Rule", + "accept": "Yes", + "reject": "No", + "choose": "Choose", + "upload": "Upload", + "cancel": "Cancel", + "dayNames": [ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday" + ], + "dayNamesShort": [ + "Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat" + ], + "dayNamesMin": [ + "Su", + "Mo", + "Tu", + "We", + "Th", + "Fr", + "Sa" + ], + "monthNames": [ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December" + ], + "monthNamesShort": [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" + ], + "today": "Today", + "weekHeader": "Wk", + "weak": "Weak", + "medium": "Medium", + "strong": "Strong", + "passwordPrompt": "Enter a password", + "emptyMessage": "No results found", + "emptyFilterMessage": "No results found" + } +} \ No newline at end of file diff --git a/kdb-web/src/assets/images/favicon.ico b/kdb-web/src/assets/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..997406ad22c29aae95893fb3d666c30258a09537 GIT binary patch literal 948 zcmV;l155mgP)CBYU7IjCFmI-B}4sMJt3^s9NVg!P0 z6hDQy(L`XWMkB@zOLgN$4KYz;j0zZxq9KKdpZE#5@k0crP^5f9KO};h)ZDQ%ybhht z%t9#h|nu0K(bJ ztIkhEr!*UyrZWQ1k2+YkGqDi8Z<|mIN&$kzpKl{cNP=OQzXHz>vn+c)F)zO|Bou>E z2|-d_=qY#Y+yOu1a}XI?cU}%04)zz%anD(XZC{#~WreV!a$7k2Ug`?&CUEc0EtrkZ zL49MB)h!_K{H(*l_93D5tO0;BUnvYlo+;yss%n^&qjt6fZOa+}+FDO(~2>G z2dx@=JZ?DHP^;b7*Y1as5^uphBsh*s*z&MBd?e@I>-9kU>63PjP&^#5YTOb&x^6Cf z?674rmSHB5Fk!{Gv7rv!?qX#ei_L(XtwVqLX3L}$MI|kJ*w(rhx~tc&L&xP#?cQow zX_|gx$wMr3pRZIIr_;;O|8fAjd;1`nOeu5K(pCu7>^3E&D2OBBq?sYa(%S?GwG&_0-s%_v$L@R!5H_fc)lOb9ZoOO#p`Nn`KU z3LTTBtjwo`7(HA6 z7gmO$yTR!5L>Bsg!X8616{JUngg_@&85%>W=mChTR;x4`P=?PJ~oPuy5 zU-L`C@_!34D21{fD~Y8NVnR3t;aqZI3fIhmgmx}$oc-dKDC6Ap$Gy>a!`A*x2L1v0 WcZ@i?LyX}70000CBYU7IjCFmI-B}4sMJt3^s9NVg!P0 z6hDQy(L`XWMkB@zOLgN$4KYz;j0zZxq9KKdpZE#5@k0crP^5f9KO};h)ZDQ%ybhht z%t9#h|nu0K(bJ ztIkhEr!*UyrZWQ1k2+YkGqDi8Z<|mIN&$kzpKl{cNP=OQzXHz>vn+c)F)zO|Bou>E z2|-d_=qY#Y+yOu1a}XI?cU}%04)zz%anD(XZC{#~WreV!a$7k2Ug`?&CUEc0EtrkZ zL49MB)h!_K{H(*l_93D5tO0;BUnvYlo+;yss%n^&qjt6fZOa+}+FDO(~2>G z2dx@=JZ?DHP^;b7*Y1as5^uphBsh*s*z&MBd?e@I>-9kU>63PjP&^#5YTOb&x^6Cf z?674rmSHB5Fk!{Gv7rv!?qX#ei_L(XtwVqLX3L}$MI|kJ*w(rhx~tc&L&xP#?cQow zX_|gx$wMr3pRZIIr_;;O|8fAjd;1`nOeu5K(pCu7>^3E&D2OBBq?sYa(%S?GwG&_0-s%_v$L@R!5H_fc)lOb9ZoOO#p`Nn`KU z3LTTBtjwo`7(HA6 z7gmO$yTR!5L>Bsg!X8616{JUngg_@&85%>W=mChTR;x4`P=?PJ~oPuy5 zU-L`C@_!34D21{fD~Y8NVnR3t;aqZI3fIhmgmx}$oc-dKDC6Ap$Gy>a!`A*x2L1v0 WcZ@i?LyX}70000 + + + + Krümmelmonster WI + + + + + + + + diff --git a/kdb-web/src/main.ts b/kdb-web/src/main.ts new file mode 100644 index 0000000000..c7b673cf44 --- /dev/null +++ b/kdb-web/src/main.ts @@ -0,0 +1,12 @@ +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.error(err)); diff --git a/kdb-web/src/polyfills.ts b/kdb-web/src/polyfills.ts new file mode 100644 index 0000000000..429bb9ef2d --- /dev/null +++ b/kdb-web/src/polyfills.ts @@ -0,0 +1,53 @@ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes recent versions of Safari, Chrome (including + * Opera), Edge on the desktop, and iOS and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + * because those flags need to be set before `zone.js` being loaded, and webpack + * will put import in the top of bundle, so user need to create a separate file + * in this directory (for example: zone-flags.ts), and put the following flags + * into that file, and then add the following code before importing zone.js. + * import './zone-flags'; + * + * The flags allowed in zone-flags.ts are listed here. + * + * The following flags will work for all browsers. + * + * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + * + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + * + * (window as any).__Zone_enable_cross_context_check = true; + * + */ + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js'; // Included with Angular CLI. + + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/kdb-web/src/styles.scss b/kdb-web/src/styles.scss new file mode 100644 index 0000000000..8964e79cb7 --- /dev/null +++ b/kdb-web/src/styles.scss @@ -0,0 +1,394 @@ +@import "./styles/themes/default-light-theme.scss"; +@import "./styles/themes/default-dark-theme.scss"; +@import "./styles/themes/sh-edraft-dark-theme.scss"; +@import "./styles/themes/sh-edraft-light-theme.scss"; +@import "./styles/primeng-fixes.scss"; +@import "./styles/constants.scss"; + +html, +body { + height: 100%; + padding: 0; + margin: 0; +} + +main { + display: flex; + flex-direction: column; + min-height: 100vh; +} + +h1, +h2 { + margin: 0; + font-size: 30px; +} + +h2 { + margin: 0; + font-size: 25px; +} + +header { + height: $headerHeight; + display: flex; + flex-direction: row; + + .logo-button-wrapper { + display: flex; + align-items: center; + justify-content: center; + margin: 0px 5px; + + .p-button.p-button-text { + border: none; + } + } + + .logo { + display: flex; + align-items: center; + justify-content: center; + } + + .header-menu { + text-align: right; + flex: 1; + justify-content: flex-end; + } + + .p-menu-overlay { + width: 180px !important; + } +} + +.app { + height: 100%; + display: flex; + flex: 1; + + .sidebar { + height: 100%; + } + + h1 { + // table views with filters are scrollable with 10 items, when 30px margin + margin-bottom: 20px; + } + + .component-wrapper { + width: 100%; + + .component { + width: 100%; + height: 100%; + padding: 15px; + + .content-wrapper { + margin-bottom: 30px; + border-radius: 5px; + + .content-header { + padding: 10px; + + h2 { + font-size: 20px; + } + } + + .content { + width: 100%; + display: flex; + flex-direction: column; + padding: 15px; + + form { + width: 100%; + } + + .content-row { + display: flex; + flex-direction: row; + flex: 1; + margin: 1.5px 0px; + } + + .content-column { + display: flex; + flex: 1; + } + + .content-data-name { + display: flex; + flex: 1; + align-items: center; + + font-size: 18px; + } + + .content-data-value { + display: flex; + flex: 1; + align-items: center; + + font-size: 18px; + } + + .content-divider { + margin: 5px 0px; + } + + .content-input-field { + width: 50% !important; + margin: 0 !important; + } + + .input-field { + width: 100%; + + input, + .p-password { + width: 100%; + } + } + + .input-field-info-text { + margin: 15px 0px; + width: 240px; + } + + .login-form-submit { + .login-form-submit-btn { + width: 240px; + } + } + + .login-form-sub-button-wrapper { + display: flex; + flex-direction: column; + + .login-form-sub-btn { + margin-top: 15px; + width: 100%; + } + + .login-form-sub-btn-wrapper { + width: 100%; + } + } + + .table-caption { + display: flex; + + .table-caption-text { + flex: 1; + font-weight: 400; + } + + .table-caption-search { + } + } + + .table-header-label { + display: flex; + + .table-header-text { + flex: 1; + } + + .table-header-icon { + } + } + + .table-header-actions { + width: 100px; + } + + .table-header-small-dropdown { + width: 150px; + } + } + } + } + } +} + +.p-dialog-header { + padding: 20px 20px 20px 20px !important; +} + +.p-dialog-content { + padding: 20px !important; +} + +.p-dialog-footer { + padding: 0px 20px 20px 20px !important; +} + +.p-dialog-content { + .content-row { + display: flex; + flex-direction: row; + flex: 1; + margin: 1.5px 0px; + } + + .content-column { + display: flex; + flex: 1; + } + + .content-data-name { + display: flex; + flex: 1; + align-items: center; + + font-size: 18px; + } + + .content-data-value { + display: flex; + flex: 1; + align-items: center; + + font-size: 18px; + } + + .content-divider { + margin: 5px 0px; + } + + .content-input-field { + width: 50% !important; + margin: 0 !important; + } +} + +footer { + width: 100%; + height: $footerHeight; + padding: 0px 10px; + + display: flex; + align-items: center; + justify-content: center; + + .left { + width: 50%; + + display: flex; + + // .frontend-version { + // } + + .version-divider { + margin: 0px 5px; + } + + // .backend-version { + // } + } + + .right { + width: 50%; + text-align: right; + } +} + +.login-wrapper { + width: 100vw; + height: 100vh; + + display: flex; + justify-content: center; + align-items: center; + + .login-form-wrapper { + width: 350px; + height: 350px; + + display: flex; + justify-content: center; + align-items: center; + + border-radius: 25px; + + .login-form { + width: 80%; + height: 80%; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + h1 { + text-align: center; + } + + .input-field-info-text { + margin: 15px 0px; + width: 240px; + } + + .login-form-submit { + .login-form-submit-btn { + width: 240px; + } + } + + .login-form-sub-button-wrapper { + display: flex; + flex-direction: column; + + .login-form-sub-btn { + margin-top: 15px; + width: 100%; + } + + .login-form-sub-btn-wrapper { + width: 100%; + } + } + } + } + + .register-form-wrapper { + height: 550px; + } + + .register-confirm-form-wrapper { + height: 250px; + } +} + +.input-field { + margin: 15px 0px; + + input, + .p-password { + height: 40px; + width: 240px; + font-size: 18px; + } +} + +.btn { + border: 0; +} + +.spinner-component-wrapper { + position: absolute; + top: 0; + width: 100vw; + height: 100vh; + + display: flex; + flex-direction: row; + justify-content: center; + + .spinner-wrapper { + display: flex; + justify-content: center; + align-items: center; + } +} diff --git a/kdb-web/src/styles/constants.scss b/kdb-web/src/styles/constants.scss new file mode 100644 index 0000000000..570127bb5e --- /dev/null +++ b/kdb-web/src/styles/constants.scss @@ -0,0 +1,2 @@ +$headerHeight: 50px; +$footerHeight: 25px; \ No newline at end of file diff --git a/kdb-web/src/styles/primeng-fixes.scss b/kdb-web/src/styles/primeng-fixes.scss new file mode 100644 index 0000000000..560ad4e34c --- /dev/null +++ b/kdb-web/src/styles/primeng-fixes.scss @@ -0,0 +1,71 @@ +@import "./constants.scss"; + +.btn { + &:focus { + box-shadow: none !important; + } +} + +.p-menu { + background: none !important; + border: none !important; + width: auto !important; + border-radius: 0px !important; + padding: 0 !important; + + .p-menuitem-link { + $distance: 10px; + padding: $distance 0px $distance $distance !important; + margin: 4px 0px 4px 6px !important; + } +} + +.p-menu-overlay { + top: $headerHeight !important; +} + +ui-menu .ui-menu-parent .ui-menu-child { + width: 400px; /* exagerated !! */ +} + +.p-toast-detail { + white-space: pre-line; +} + +.p-datatable .p-sortable-column:focus { + box-shadow: none !important; +} + +.p-password { + padding: 0px !important; +} + +.p-paginator { + background-color: transparent !important; + border: none !important; +} + +p-table { + .p-datatable .p-datatable-header { + border: none !important; + } + + .p-datatable .p-datatable-header, + .p-datatable .p-datatable-tbody > tr, + .p-datatable .p-datatable-thead > tr > th { + background-color: transparent !important; + color: inherit !important; + } +} + +.pi-sort-alt:before { + content: "\e915" !important; +} + +.pi-sort-amount-up-alt:before { + content: "\e914" !important; +} + +.pi-sort-amount-down:before { + content: "\e913" !important; +} diff --git a/kdb-web/src/styles/themes/default-dark-theme.scss b/kdb-web/src/styles/themes/default-dark-theme.scss new file mode 100644 index 0000000000..7507a6cb05 --- /dev/null +++ b/kdb-web/src/styles/themes/default-dark-theme.scss @@ -0,0 +1,517 @@ +.default-dark-theme { + $primaryTextColor: #fff; + $secondayTextColor: #000; + $secondayTextColor2: #1e88e5; + + $primaryHeaderColor: #1e88e5; + $secondaryHeaderColor: #6ab7ff; + $secondaryHeaderColor2: #005cb2; + + $primaryBackgroundColor: #272727; + $secondaryBackgroundColor: #4f4f4f; + $secondaryBackgroundColor2: #fff; + $secondaryBackgroundColor3: #cccccc; + + $primaryErrorColor: #b00020; + $secondaryErrorColor: #e94948; + + $default-border: 1px solid $secondaryBackgroundColor3; + + background-color: $primaryBackgroundColor !important; + + html, + body { + margin: 0; + + font-size: 16px; + } + + h1, + h2 { + color: $primaryHeaderColor; + } + + input, + p { + color: $primaryTextColor; + } + + input { + background-color: $secondaryBackgroundColor !important; + } + + .input-field-info-text { + color: $primaryTextColor; + } + + /* Change Autocomplete styles in Chrome*/ + input:-webkit-autofill, + input:-webkit-autofill:hover, + input:-webkit-autofill:focus, + textarea:-webkit-autofill, + textarea:-webkit-autofill:hover, + textarea:-webkit-autofill:focus, + select:-webkit-autofill, + select:-webkit-autofill:hover, + select:-webkit-autofill:focus { + border: 1px solid $primaryHeaderColor; + -webkit-text-fill-color: $primaryTextColor; + -webkit-box-shadow: 0 0 0px 1000px $secondaryBackgroundColor inset; + transition: background-color 5000s ease-in-out 0s; + } + + header { + background-color: $primaryBackgroundColor; + + .logo-button-wrapper { + .p-button.p-button-text { + color: $primaryTextColor; + + &:hover { + color: $primaryTextColor; + background-color: $primaryBackgroundColor; + } + } + } + + .logo { + color: $primaryHeaderColor; + } + } + + h1 { + color: $primaryHeaderColor; + } + + .app { + .sidebar { + background-color: $primaryBackgroundColor; + + .menu { + color: $primaryTextColor; + } + } + + .component-wrapper { + color: $primaryTextColor; + + .component { + background-color: $secondaryBackgroundColor; + + .content-wrapper { + background-color: $primaryBackgroundColor; + border-top: 2px solid $primaryHeaderColor; + + .content-header { + border-bottom: $default-border; + } + + .content { + .content-row { + } + + .content-column { + } + + .content-data-name { + } + + .content-data-value { + } + + .content-divider { + border-bottom: $default-border; + } + } + } + } + } + } + + .p-dialog-header { + background-color: $secondaryBackgroundColor !important; + color: $primaryTextColor !important; + } + + .p-dialog-content { + .content-data-name, + .content-data-value { + color: $primaryTextColor; + + .text-btn { + font-size: 18px !important; + font-weight: 400 !important; + } + } + } + + footer { + background-color: $primaryBackgroundColor; + color: $primaryTextColor; + + a { + color: $primaryTextColor; + } + } + + .invalid-feedback { + color: $primaryErrorColor; + } + + .invalid-feedback-input, + .invalid-feedback-input:focus, + .invalid-feedback-input:hover { + input, + input:enabled:focus { + outline: 1px solid $primaryErrorColor !important; + border: 1px solid $primaryErrorColor !important; + border-color: $primaryErrorColor !important; + } + } + + .login-wrapper { + background-color: $secondaryBackgroundColor; + + .login-form-wrapper { + background-color: $primaryBackgroundColor; + + .login-form { + .input-field { + input, + .p-password { + } + } + + .login-form-submit { + .login-form-submit-btn { + } + } + + .login-form-sub-button-wrapper { + .login-form-sub-btn { + background-color: $primaryBackgroundColor; + color: $secondayTextColor2; + border: 2px solid $secondayTextColor2; + + &:hover { + background-color: $primaryHeaderColor !important; + color: $primaryTextColor !important; + } + } + + .login-form-sub-login-btn { + border: none; + } + } + } + } + } + + .spinner-component-wrapper { + background-color: rgba($secondaryBackgroundColor, 0.5); + + .spinner-wrapper { + .custom-spinner .p-progress-spinner-circle { + color: $primaryHeaderColor; + } + } + } + + .wrapper-right { + justify-content: flex-end !important; + } + + /* + PrimeNG Fixes + */ + .p-progress-spinner-circle { + stroke: $primaryHeaderColor !important; + } + + .p-menu { + color: $primaryTextColor !important; + + .p-menuitem-link .p-menuitem-text, + .p-menuitem-link .p-menuitem-icon { + color: $primaryTextColor !important; + } + + .p-menuitem-link:focus { + box-shadow: none !important; + } + + .p-menuitem-link:hover { + background-color: $secondaryBackgroundColor !important; + $border-radius: 20px; + border-radius: $border-radius 0px 0px $border-radius; + + .p-menuitem-text, + .p-menuitem-icon { + color: $primaryHeaderColor !important; + } + } + } + + .p-menu-overlay { + background-color: $primaryBackgroundColor !important; + color: $primaryTextColor !important; + border-top: 2px solid $primaryHeaderColor !important; + + .p-menuitem-link:hover { + background-color: $primaryBackgroundColor !important; + .p-menuitem-text, + .p-menuitem-icon { + color: $primaryHeaderColor !important; + } + } + } + + p-dropdown { + .p-dropdown { + background-color: $primaryBackgroundColor !important; + border-color: $primaryTextColor !important; + color: $primaryTextColor !important; + + span { + color: $primaryTextColor; + } + + .p-dropdown-panel { + background-color: $secondaryBackgroundColor !important; + + .p-dropdown-items .p-dropdown-item:not(.p-highlight):not(.p-disabled):hover { + background-color: $secondaryBackgroundColor !important; + color: $primaryHeaderColor !important; + + span { + color: $primaryHeaderColor !important; + } + } + + .p-dropdown-items .p-dropdown-item.p-highlight { + background-color: $secondaryBackgroundColor !important; + color: $primaryHeaderColor !important; + + span { + color: $primaryHeaderColor !important; + } + } + } + } + } + + p-table { + background-color: $primaryBackgroundColor; + color: $primaryTextColor !important; + + .table-caption { + .table-caption-text { + } + + .table-caption-search-wrapper { + .table-caption-search { + height: 30px !important; + + .table-caption-search-icon { + } + + .table-caption-search-input { + height: 100% !important; + + &:focus { + outline-color: $primaryHeaderColor; + } + } + } + } + + .table-caption-btn-wrapper { + height: 30px !important; + } + } + + .table-edit-input { + width: 100% !important; + } + } + + p-checkbox { + .p-checkbox .p-checkbox-box { + background: $primaryBackgroundColor !important; + background-color: $primaryBackgroundColor !important; + } + + .p-checkbox .p-checkbox-box.p-highlight { + background: $primaryBackgroundColor !important; + background-color: $primaryBackgroundColor !important; + border-color: $primaryTextColor !important; + box-shadow: none !important; + } + + .p-checkbox .p-checkbox-box .p-checkbox-icon { + color: $primaryTextColor !important; + } + + .p-checkbox:not(.p-checkbox-disabled) .p-checkbox-box.p-focus, + .p-checkbox:not(.p-checkbox-disabled) .p-checkbox-box:hover { + border-color: $primaryHeaderColor !important; + box-shadow: none !important; + + .p-checkbox-icon { + color: $primaryHeaderColor !important; + } + } + } + + p-dialog, + p-confirmdialog, + p-dynamicdialog { + .p-dialog.p-confirm-dialog .p-confirm-dialog-message { + margin-left: 0px !important; + } + + .p-dialog { + background-color: $secondaryBackgroundColor !important; + + .p-dialog-header { + background-color: $primaryBackgroundColor !important; + color: $primaryTextColor !important; + } + + .p-dialog-content, + .p-dialog-footer { + background-color: $secondaryBackgroundColor !important; + color: $primaryTextColor !important; + } + } + } + + input, + .p-password { + &:focus { + box-shadow: none !important; + } + + &:hover, + &:active, + &:enabled:focus { + border-color: $primaryHeaderColor !important; + } + } + + .btn-wrapper { + display: flex !important; + align-items: center !important; + } + + .btn { + background-color: $primaryHeaderColor; + color: $primaryTextColor; + border: 0; + + &:hover, + &:enabled:hover { + background-color: $primaryHeaderColor; + color: $primaryTextColor; + border: 0; + } + } + + .icon-btn { + background-color: transparent !important; + color: $primaryTextColor !important; + border: 0 !important; + + .pi { + font-size: 1.275rem !important; + } + } + + .text-btn { + background-color: transparent !important; + color: $primaryTextColor !important; + border: 0 !important; + padding: 0px !important; + + &:hover { + background-color: transparent !important; + color: $primaryHeaderColor !important; + border: 0; + } + } + + .icon-btn-without-hover { + &:hover { + background-color: transparent !important; + color: $primaryTextColor !important; + border: 0 !important; + } + } + + .icon-btn { + &:hover { + background-color: transparent !important; + color: $primaryHeaderColor !important; + border: 0; + } + } + + .danger-icon-btn { + background-color: transparent !important; + color: $primaryTextColor !important; + border: 0 !important; + + &:hover { + background-color: transparent !important; + color: $primaryErrorColor !important; + border: 0; + } + + .pi { + font-size: 1.275rem !important; + } + } + + .danger-btn { + background-color: $primaryErrorColor !important; + color: $primaryErrorColor !important; + border: 0 !important; + + &:hover { + background-color: $primaryErrorColor !important; + color: $primaryTextColor !important; + border: 0; + } + + .pi { + font-size: 1.275rem !important; + } + } + + .p-datatable .p-sortable-column.p-highlight, + .p-datatable .p-sortable-column.p-highlight .p-sortable-column-icon { + color: $primaryHeaderColor !important; + } + + .p-dropdown:not(.p-disabled):hover, + .p-dropdown:not(.p-disabled).p-focus, + .p-link:focus { + border-color: $primaryHeaderColor !important; + box-shadow: none !important; + } + + .p-paginator .p-paginator-pages .p-paginator-page.p-highlight { + background: transparent !important; + background-color: transparent !important; + color: $primaryHeaderColor !important; + } + + .p-paginator .p-paginator-pages .p-paginator-page:not(.p-highlight):hover, + .p-paginator .p-paginator-first:not(.p-disabled):not(.p-highlight):hover, + .p-paginator .p-paginator-prev:not(.p-disabled):not(.p-highlight):hover, + .p-paginator .p-paginator-next:not(.p-disabled):not(.p-highlight):hover, + .p-paginator .p-paginator-last:not(.p-disabled):not(.p-highlight):hover { + background-color: $primaryBackgroundColor !important; + color: $primaryHeaderColor !important; + } +} diff --git a/kdb-web/src/styles/themes/default-light-theme.scss b/kdb-web/src/styles/themes/default-light-theme.scss new file mode 100644 index 0000000000..5993a05808 --- /dev/null +++ b/kdb-web/src/styles/themes/default-light-theme.scss @@ -0,0 +1,515 @@ +.default-light-theme { + $primaryTextColor: #272727; + $secondayTextColor: #fff; + $secondayTextColor2: #1e88e5; + + $primaryHeaderColor: #1e88e5; + $secondaryHeaderColor: #6ab7ff; + $secondaryHeaderColor2: #005cb2; + + $primaryBackgroundColor: #fff; + $secondaryBackgroundColor: #cccccc; + $secondaryBackgroundColor2: #4f4f4f; + $secondaryBackgroundColor3: #272727; + + $primaryErrorColor: #b00020; + $secondaryErrorColor: #e94948; + + $default-border: 1px solid $secondaryBackgroundColor; + + html, + body { + margin: 0; + + font-size: 16px; + } + + h1, + h2 { + color: $primaryHeaderColor; + } + + input, + p { + color: $primaryTextColor; + } + + input { + background-color: $primaryBackgroundColor !important; + } + + .input-field-info-text { + color: $primaryTextColor; + } + + /* Change Autocomplete styles in Chrome*/ + input:-webkit-autofill, + input:-webkit-autofill:hover, + input:-webkit-autofill:focus, + textarea:-webkit-autofill, + textarea:-webkit-autofill:hover, + textarea:-webkit-autofill:focus, + select:-webkit-autofill, + select:-webkit-autofill:hover, + select:-webkit-autofill:focus { + border: 1px solid $primaryHeaderColor; + -webkit-text-fill-color: $primaryTextColor; + -webkit-box-shadow: 0 0 0px 1000px $primaryBackgroundColor inset; + transition: background-color 5000s ease-in-out 0s; + } + + header { + background-color: $primaryBackgroundColor; + + .logo-button-wrapper { + .p-button.p-button-text { + color: $primaryTextColor; + + &:hover { + color: $primaryTextColor; + background-color: $primaryBackgroundColor; + } + } + } + + .logo { + color: $primaryHeaderColor; + } + } + + h1 { + color: $primaryHeaderColor; + } + + .app { + .sidebar { + background-color: $primaryBackgroundColor; + + .menu { + color: $primaryTextColor; + } + } + + .component-wrapper { + color: $primaryTextColor; + + .component { + background-color: $secondaryBackgroundColor; + + .content-wrapper { + background-color: $primaryBackgroundColor; + border-top: 2px solid $primaryHeaderColor; + + .content-header { + border-bottom: $default-border; + } + + .content { + .content-row { + } + + .content-column { + } + + .content-data-name { + } + + .content-data-value { + } + + .content-divider { + border-bottom: $default-border; + } + } + } + } + } + } + + .p-dialog-header { + background-color: $secondaryBackgroundColor !important; + color: $primaryTextColor !important; + } + + .p-dialog-content { + .content-data-name, + .content-data-value { + color: $primaryTextColor; + + .text-btn { + font-size: 18px !important; + font-weight: 400 !important; + } + } + } + + footer { + background-color: $primaryBackgroundColor; + color: $primaryTextColor; + + a { + color: $primaryTextColor; + } + } + + .invalid-feedback { + color: $primaryErrorColor; + } + + .invalid-feedback-input, + .invalid-feedback-input:focus, + .invalid-feedback-input:hover { + input, + input:enabled:focus { + outline: 1px solid $primaryErrorColor !important; + border: 1px solid $primaryErrorColor !important; + border-color: $primaryErrorColor !important; + } + } + + .login-wrapper { + background-color: $secondaryBackgroundColor; + + .login-form-wrapper { + background-color: $primaryBackgroundColor; + + .login-form { + .input-field { + input, + .p-password { + } + } + + .login-form-submit { + .login-form-submit-btn { + } + } + + .login-form-sub-button-wrapper { + .login-form-sub-btn { + background-color: $primaryBackgroundColor; + color: $secondayTextColor2; + border: 2px solid $secondayTextColor2; + + &:hover { + background-color: $primaryHeaderColor !important; + color: $primaryTextColor !important; + } + } + + .login-form-sub-login-btn { + border: none; + } + } + } + } + } + + .spinner-component-wrapper { + background-color: rgba($secondaryBackgroundColor, 0.5); + + .spinner-wrapper { + .custom-spinner .p-progress-spinner-circle { + color: $primaryHeaderColor; + } + } + } + + .wrapper-right { + justify-content: flex-end !important; + } + + /* + PrimeNG Fixes + */ + .p-progress-spinner-circle { + stroke: $primaryHeaderColor !important; + } + + .p-menu { + color: $primaryTextColor !important; + + .p-menuitem-link .p-menuitem-text, + .p-menuitem-link .p-menuitem-icon { + color: $primaryTextColor !important; + } + + .p-menuitem-link:focus { + box-shadow: none !important; + } + + .p-menuitem-link:hover { + background-color: $secondaryBackgroundColor !important; + $border-radius: 20px; + border-radius: $border-radius 0px 0px $border-radius; + + .p-menuitem-text, + .p-menuitem-icon { + color: $primaryHeaderColor !important; + } + } + } + + .p-menu-overlay { + background-color: $primaryBackgroundColor !important; + color: $primaryTextColor !important; + border-top: 2px solid $primaryHeaderColor !important; + + .p-menuitem-link:hover { + background-color: $primaryBackgroundColor !important; + .p-menuitem-text, + .p-menuitem-icon { + color: $primaryHeaderColor !important; + } + } + } + + p-dropdown { + .p-dropdown { + background-color: $primaryBackgroundColor !important; + border-color: $primaryTextColor !important; + color: $primaryTextColor !important; + + span { + color: $primaryTextColor; + } + + .p-dropdown-panel { + background-color: $primaryBackgroundColor !important; + + .p-dropdown-items .p-dropdown-item:not(.p-highlight):not(.p-disabled):hover { + background-color: $primaryBackgroundColor !important; + color: $primaryHeaderColor !important; + + span { + color: $primaryHeaderColor !important; + } + } + + .p-dropdown-items .p-dropdown-item.p-highlight { + background-color: $primaryBackgroundColor !important; + color: $primaryHeaderColor !important; + + span { + color: $primaryHeaderColor !important; + } + } + } + } + } + + p-table { + background-color: $primaryBackgroundColor; + color: $primaryTextColor !important; + + .table-caption { + .table-caption-text { + } + + .table-caption-search-wrapper { + .table-caption-search { + height: 30px !important; + + .table-caption-search-icon { + } + + .table-caption-search-input { + height: 100% !important; + + &:focus { + outline-color: $primaryHeaderColor; + } + } + } + } + + .table-caption-btn-wrapper { + height: 30px !important; + } + } + + .table-edit-input { + width: 100% !important; + } + } + + p-checkbox { + .p-checkbox .p-checkbox-box { + background: $primaryBackgroundColor !important; + background-color: $primaryBackgroundColor !important; + } + + .p-checkbox .p-checkbox-box.p-highlight { + background: $primaryBackgroundColor !important; + background-color: $primaryBackgroundColor !important; + border-color: $primaryTextColor !important; + box-shadow: none !important; + } + + .p-checkbox .p-checkbox-box .p-checkbox-icon { + color: $primaryTextColor !important; + } + + .p-checkbox:not(.p-checkbox-disabled) .p-checkbox-box.p-focus, + .p-checkbox:not(.p-checkbox-disabled) .p-checkbox-box:hover { + border-color: $primaryHeaderColor !important; + box-shadow: none !important; + + .p-checkbox-icon { + color: $primaryHeaderColor !important; + } + } + } + + p-dialog, + p-confirmdialog, + p-dynamicdialog { + .p-dialog.p-confirm-dialog .p-confirm-dialog-message { + margin-left: 0px !important; + } + + .p-dialog { + background-color: $primaryBackgroundColor !important; + + .p-dialog-header { + background-color: $secondaryBackgroundColor !important; + color: $primaryTextColor !important; + } + + .p-dialog-content, + .p-dialog-footer { + background-color: $primaryBackgroundColor !important; + color: $primaryTextColor !important; + } + } + } + + input, + .p-password { + &:focus { + box-shadow: none !important; + } + + &:hover, + &:active, + &:enabled:focus { + border-color: $primaryHeaderColor !important; + } + } + + .btn-wrapper { + display: flex !important; + align-items: center !important; + } + + .btn { + background-color: $primaryHeaderColor; + color: $primaryTextColor; + border: 0; + + &:hover, + &:enabled:hover { + background-color: $primaryHeaderColor; + color: $primaryTextColor; + border: 0; + } + } + + .icon-btn { + background-color: transparent !important; + color: $primaryTextColor !important; + border: 0 !important; + + .pi { + font-size: 1.275rem !important; + } + } + + .text-btn { + background-color: transparent !important; + color: $primaryTextColor !important; + border: 0 !important; + padding: 0px !important; + + &:hover { + background-color: transparent !important; + color: $primaryHeaderColor !important; + border: 0; + } + } + + .icon-btn-without-hover { + &:hover { + background-color: transparent !important; + color: $primaryTextColor !important; + border: 0 !important; + } + } + + .icon-btn { + &:hover { + background-color: transparent !important; + color: $primaryHeaderColor !important; + border: 0; + } + } + + .danger-icon-btn { + background-color: transparent !important; + color: $primaryTextColor !important; + border: 0 !important; + + &:hover { + background-color: transparent !important; + color: $primaryErrorColor !important; + border: 0; + } + + .pi { + font-size: 1.275rem !important; + } + } + + .danger-btn { + background-color: $primaryErrorColor !important; + color: $primaryErrorColor !important; + border: 0 !important; + + &:hover { + background-color: $primaryErrorColor !important; + color: $primaryTextColor !important; + border: 0; + } + + .pi { + font-size: 1.275rem !important; + } + } + + .p-datatable .p-sortable-column.p-highlight, + .p-datatable .p-sortable-column.p-highlight .p-sortable-column-icon { + color: $primaryHeaderColor !important; + } + + .p-dropdown:not(.p-disabled):hover, + .p-dropdown:not(.p-disabled).p-focus, + .p-link:focus { + border-color: $primaryHeaderColor !important; + box-shadow: none !important; + } + + .p-paginator .p-paginator-pages .p-paginator-page.p-highlight { + background: transparent !important; + background-color: transparent !important; + color: $primaryHeaderColor !important; + } + + .p-paginator .p-paginator-pages .p-paginator-page:not(.p-highlight):hover, + .p-paginator .p-paginator-first:not(.p-disabled):not(.p-highlight):hover, + .p-paginator .p-paginator-prev:not(.p-disabled):not(.p-highlight):hover, + .p-paginator .p-paginator-next:not(.p-disabled):not(.p-highlight):hover, + .p-paginator .p-paginator-last:not(.p-disabled):not(.p-highlight):hover { + background-color: $primaryBackgroundColor !important; + color: $primaryHeaderColor !important; + } +} diff --git a/kdb-web/src/styles/themes/sh-edraft-dark-theme.scss b/kdb-web/src/styles/themes/sh-edraft-dark-theme.scss new file mode 100644 index 0000000000..ee2da9f469 --- /dev/null +++ b/kdb-web/src/styles/themes/sh-edraft-dark-theme.scss @@ -0,0 +1,519 @@ +.sh-edraft-dark-theme { + $primaryTextColor: #fff; + $secondayTextColor: #000; + $secondayTextColor2: #ef9d0d; + + $primaryHeaderColor: #ef9d0d; + $secondaryHeaderColor: #ffce4c; + $secondaryHeaderColor2: #b76f00; + + $primaryBackgroundColor: #272727; + $secondaryBackgroundColor: #4f4f4f; + $secondaryBackgroundColor2: #fff; + $secondaryBackgroundColor3: #cccccc; + + $primaryErrorColor: #b00020; + $secondaryErrorColor: #e94948; + + $default-border: 1px solid $secondaryBackgroundColor3; + + background-color: $primaryBackgroundColor !important; + + html, + body { + margin: 0; + + font-size: 16px; + } + + h1, + h2 { + color: $primaryHeaderColor; + } + + input, + p { + color: $primaryTextColor; + } + + input { + background-color: $secondaryBackgroundColor !important; + } + + .input-field-info-text { + color: $primaryTextColor; + } + + /* Change Autocomplete styles in Chrome*/ + input:-webkit-autofill, + input:-webkit-autofill:hover, + input:-webkit-autofill:focus, + textarea:-webkit-autofill, + textarea:-webkit-autofill:hover, + textarea:-webkit-autofill:focus, + select:-webkit-autofill, + select:-webkit-autofill:hover, + select:-webkit-autofill:focus { + border: 1px solid $primaryHeaderColor; + -webkit-text-fill-color: $primaryTextColor; + -webkit-box-shadow: 0 0 0px 1000px $secondaryBackgroundColor inset; + transition: background-color 5000s ease-in-out 0s; + } + + header { + background-color: $primaryBackgroundColor; + + .logo-button-wrapper { + .p-button.p-button-text { + color: $primaryTextColor; + + &:hover { + color: $primaryTextColor; + background-color: $primaryBackgroundColor; + } + } + } + + .logo { + color: $primaryHeaderColor; + } + } + + h1 { + color: $primaryHeaderColor; + } + + .app { + .sidebar { + background-color: $primaryBackgroundColor; + + .menu { + color: $primaryTextColor; + } + } + + .component-wrapper { + color: $primaryTextColor; + + .component { + background-color: $secondaryBackgroundColor; + + .content-wrapper { + background-color: $primaryBackgroundColor; + border-top: 2px solid $primaryHeaderColor; + + .content-header { + border-bottom: $default-border; + } + + .content { + .content-row { + } + + .content-column { + } + + .content-data-name { + } + + .content-data-value { + } + + .content-divider { + border-bottom: $default-border; + } + } + } + } + } + } + + .p-dialog-header { + background-color: $primaryBackgroundColor !important; + color: $primaryTextColor !important; + } + + .p-dialog-content { + background-color: $secondaryBackgroundColor !important; + + .content-data-name, + .content-data-value { + color: $primaryTextColor; + + .text-btn { + font-size: 18px !important; + font-weight: 400 !important; + } + } + } + + footer { + background-color: $primaryBackgroundColor; + color: $primaryTextColor; + + a { + color: $primaryTextColor; + } + } + + .invalid-feedback { + color: $primaryErrorColor; + } + + .invalid-feedback-input, + .invalid-feedback-input:focus, + .invalid-feedback-input:hover { + input, + input:enabled:focus { + outline: 1px solid $primaryErrorColor !important; + border: 1px solid $primaryErrorColor !important; + border-color: $primaryErrorColor !important; + } + } + + .login-wrapper { + background-color: $secondaryBackgroundColor; + + .login-form-wrapper { + background-color: $primaryBackgroundColor; + + .login-form { + .input-field { + input, + .p-password { + } + } + + .login-form-submit { + .login-form-submit-btn { + } + } + + .login-form-sub-button-wrapper { + .login-form-sub-btn { + background-color: $primaryBackgroundColor; + color: $secondayTextColor2; + border: 2px solid $secondayTextColor2; + + &:hover { + background-color: $primaryHeaderColor !important; + color: $primaryTextColor !important; + } + } + + .login-form-sub-login-btn { + border: none; + } + } + } + } + } + + .spinner-component-wrapper { + background-color: rgba($secondaryBackgroundColor, 0.5); + + .spinner-wrapper { + .custom-spinner .p-progress-spinner-circle { + color: $primaryHeaderColor; + } + } + } + + .wrapper-right { + justify-content: flex-end !important; + } + + /* + PrimeNG Fixes + */ + .p-progress-spinner-circle { + stroke: $primaryHeaderColor !important; + } + + .p-menu { + color: $primaryTextColor !important; + + .p-menuitem-link .p-menuitem-text, + .p-menuitem-link .p-menuitem-icon { + color: $primaryTextColor !important; + } + + .p-menuitem-link:focus { + box-shadow: none !important; + } + + .p-menuitem-link:hover { + background-color: $secondaryBackgroundColor !important; + $border-radius: 20px; + border-radius: $border-radius 0px 0px $border-radius; + + .p-menuitem-text, + .p-menuitem-icon { + color: $primaryHeaderColor !important; + } + } + } + + .p-menu-overlay { + background-color: $primaryBackgroundColor !important; + color: $primaryTextColor !important; + border-top: 2px solid $primaryHeaderColor !important; + + .p-menuitem-link:hover { + background-color: $primaryBackgroundColor !important; + .p-menuitem-text, + .p-menuitem-icon { + color: $primaryHeaderColor !important; + } + } + } + + p-dropdown { + .p-dropdown { + background-color: $primaryBackgroundColor !important; + border-color: $primaryTextColor !important; + color: $primaryTextColor !important; + + span { + color: $primaryTextColor; + } + + .p-dropdown-panel { + background-color: $secondaryBackgroundColor !important; + + .p-dropdown-items .p-dropdown-item:not(.p-highlight):not(.p-disabled):hover { + background-color: $secondaryBackgroundColor !important; + color: $primaryHeaderColor !important; + + span { + color: $primaryHeaderColor !important; + } + } + + .p-dropdown-items .p-dropdown-item.p-highlight { + background-color: $secondaryBackgroundColor !important; + color: $primaryHeaderColor !important; + + span { + color: $primaryHeaderColor !important; + } + } + } + } + } + + p-table { + background-color: $primaryBackgroundColor; + color: $primaryTextColor !important; + + .table-caption { + .table-caption-text { + } + + .table-caption-search-wrapper { + .table-caption-search { + height: 30px !important; + + .table-caption-search-icon { + } + + .table-caption-search-input { + height: 100% !important; + + &:focus { + outline-color: $primaryHeaderColor; + } + } + } + } + + .table-caption-btn-wrapper { + height: 30px !important; + } + } + + .table-edit-input { + width: 100% !important; + } + } + + p-checkbox { + .p-checkbox .p-checkbox-box { + background: $primaryBackgroundColor !important; + background-color: $primaryBackgroundColor !important; + } + + .p-checkbox .p-checkbox-box.p-highlight { + background: $primaryBackgroundColor !important; + background-color: $primaryBackgroundColor !important; + border-color: $primaryTextColor !important; + box-shadow: none !important; + } + + .p-checkbox .p-checkbox-box .p-checkbox-icon { + color: $primaryTextColor !important; + } + + .p-checkbox:not(.p-checkbox-disabled) .p-checkbox-box.p-focus, + .p-checkbox:not(.p-checkbox-disabled) .p-checkbox-box:hover { + border-color: $primaryHeaderColor !important; + box-shadow: none !important; + + .p-checkbox-icon { + color: $primaryHeaderColor !important; + } + } + } + + p-dialog, + p-confirmdialog, + p-dynamicdialog { + .p-dialog.p-confirm-dialog .p-confirm-dialog-message { + margin-left: 0px !important; + } + + .p-dialog { + background-color: $secondaryBackgroundColor !important; + + .p-dialog-header { + background-color: $primaryBackgroundColor !important; + color: $primaryTextColor !important; + } + + .p-dialog-content, + .p-dialog-footer { + background-color: $secondaryBackgroundColor !important; + color: $primaryTextColor !important; + } + } + } + + input, + .p-password { + &:focus { + box-shadow: none !important; + } + + &:hover, + &:active, + &:enabled:focus { + border-color: $primaryHeaderColor !important; + } + } + + .btn-wrapper { + display: flex !important; + align-items: center !important; + } + + .btn { + background-color: $primaryHeaderColor; + color: $primaryTextColor; + border: 0; + + &:hover, + &:enabled:hover { + background-color: $primaryHeaderColor; + color: $primaryTextColor; + border: 0; + } + } + + .icon-btn { + background-color: transparent !important; + color: $primaryTextColor !important; + border: 0 !important; + + .pi { + font-size: 1.275rem !important; + } + } + + .text-btn { + background-color: transparent !important; + color: $primaryTextColor !important; + border: 0 !important; + padding: 0px !important; + + &:hover { + background-color: transparent !important; + color: $primaryHeaderColor !important; + border: 0; + } + } + + .icon-btn-without-hover { + &:hover { + background-color: transparent !important; + color: $primaryTextColor !important; + border: 0 !important; + } + } + + .icon-btn { + &:hover { + background-color: transparent !important; + color: $primaryHeaderColor !important; + border: 0; + } + } + + .danger-icon-btn { + background-color: transparent !important; + color: $primaryTextColor !important; + border: 0 !important; + + &:hover { + background-color: transparent !important; + color: $primaryErrorColor !important; + border: 0; + } + + .pi { + font-size: 1.275rem !important; + } + } + + .danger-btn { + background-color: $primaryErrorColor !important; + color: $primaryErrorColor !important; + border: 0 !important; + + &:hover { + background-color: $primaryErrorColor !important; + color: $primaryTextColor !important; + border: 0; + } + + .pi { + font-size: 1.275rem !important; + } + } + + .p-datatable .p-sortable-column.p-highlight, + .p-datatable .p-sortable-column.p-highlight .p-sortable-column-icon { + color: $primaryHeaderColor !important; + } + + .p-dropdown:not(.p-disabled):hover, + .p-dropdown:not(.p-disabled).p-focus, + .p-link:focus { + border-color: $primaryHeaderColor !important; + box-shadow: none !important; + } + + .p-paginator .p-paginator-pages .p-paginator-page.p-highlight { + background: transparent !important; + background-color: transparent !important; + color: $primaryHeaderColor !important; + } + + .p-paginator .p-paginator-pages .p-paginator-page:not(.p-highlight):hover, + .p-paginator .p-paginator-first:not(.p-disabled):not(.p-highlight):hover, + .p-paginator .p-paginator-prev:not(.p-disabled):not(.p-highlight):hover, + .p-paginator .p-paginator-next:not(.p-disabled):not(.p-highlight):hover, + .p-paginator .p-paginator-last:not(.p-disabled):not(.p-highlight):hover { + background-color: $primaryBackgroundColor !important; + color: $primaryHeaderColor !important; + } +} diff --git a/kdb-web/src/styles/themes/sh-edraft-light-theme.scss b/kdb-web/src/styles/themes/sh-edraft-light-theme.scss new file mode 100644 index 0000000000..fdd809491c --- /dev/null +++ b/kdb-web/src/styles/themes/sh-edraft-light-theme.scss @@ -0,0 +1,515 @@ +.sh-edraft-light-theme { + $primaryTextColor: #272727; + $secondayTextColor: #fff; + $secondayTextColor2: #ef9d0d; + + $primaryHeaderColor: #ef9d0d; + $secondaryHeaderColor: #ffce4c; + $secondaryHeaderColor2: #b76f00; + + $primaryBackgroundColor: #fff; + $secondaryBackgroundColor: #cccccc; + $secondaryBackgroundColor2: #4f4f4f; + $secondaryBackgroundColor3: #272727; + + $primaryErrorColor: #b00020; + $secondaryErrorColor: #e94948; + + $default-border: 1px solid $secondaryBackgroundColor; + + html, + body { + margin: 0; + + font-size: 16px; + } + + h1, + h2 { + color: $primaryHeaderColor; + } + + input, + p { + color: $primaryTextColor; + } + + input { + background-color: $primaryBackgroundColor !important; + } + + .input-field-info-text { + color: $primaryTextColor; + } + + /* Change Autocomplete styles in Chrome*/ + input:-webkit-autofill, + input:-webkit-autofill:hover, + input:-webkit-autofill:focus, + textarea:-webkit-autofill, + textarea:-webkit-autofill:hover, + textarea:-webkit-autofill:focus, + select:-webkit-autofill, + select:-webkit-autofill:hover, + select:-webkit-autofill:focus { + border: 1px solid $primaryHeaderColor; + -webkit-text-fill-color: $primaryTextColor; + -webkit-box-shadow: 0 0 0px 1000px $primaryBackgroundColor inset; + transition: background-color 5000s ease-in-out 0s; + } + + header { + background-color: $primaryBackgroundColor; + + .logo-button-wrapper { + .p-button.p-button-text { + color: $primaryTextColor; + + &:hover { + color: $primaryTextColor; + background-color: $primaryBackgroundColor; + } + } + } + + .logo { + color: $primaryHeaderColor; + } + } + + h1 { + color: $primaryHeaderColor; + } + + .app { + .sidebar { + background-color: $primaryBackgroundColor; + + .menu { + color: $primaryTextColor; + } + } + + .component-wrapper { + color: $primaryTextColor; + + .component { + background-color: $secondaryBackgroundColor; + + .content-wrapper { + background-color: $primaryBackgroundColor; + border-top: 2px solid $primaryHeaderColor; + + .content-header { + border-bottom: $default-border; + } + + .content { + .content-row { + } + + .content-column { + } + + .content-data-name { + } + + .content-data-value { + } + + .content-divider { + border-bottom: $default-border; + } + } + } + } + } + } + + .p-dialog-header { + background-color: $secondaryBackgroundColor !important; + color: $primaryTextColor !important; + } + + .p-dialog-content { + .content-data-name, + .content-data-value { + color: $primaryTextColor; + + .text-btn { + font-size: 18px !important; + font-weight: 400 !important; + } + } + } + + footer { + background-color: $primaryBackgroundColor; + color: $primaryTextColor; + + a { + color: $primaryTextColor; + } + } + + .invalid-feedback { + color: $primaryErrorColor; + } + + .invalid-feedback-input, + .invalid-feedback-input:focus, + .invalid-feedback-input:hover { + input, + input:enabled:focus { + outline: 1px solid $primaryErrorColor !important; + border: 1px solid $primaryErrorColor !important; + border-color: $primaryErrorColor !important; + } + } + + .login-wrapper { + background-color: $secondaryBackgroundColor; + + .login-form-wrapper { + background-color: $primaryBackgroundColor; + + .login-form { + .input-field { + input, + .p-password { + } + } + + .login-form-submit { + .login-form-submit-btn { + } + } + + .login-form-sub-button-wrapper { + .login-form-sub-btn { + background-color: $primaryBackgroundColor; + color: $secondayTextColor2; + border: 2px solid $secondayTextColor2; + + &:hover { + background-color: $primaryHeaderColor !important; + color: $primaryTextColor !important; + } + } + + .login-form-sub-login-btn { + border: none; + } + } + } + } + } + + .spinner-component-wrapper { + background-color: rgba($secondaryBackgroundColor, 0.5); + + .spinner-wrapper { + .custom-spinner .p-progress-spinner-circle { + color: $primaryHeaderColor; + } + } + } + + .wrapper-right { + justify-content: flex-end !important; + } + + /* + PrimeNG Fixes + */ + .p-progress-spinner-circle { + stroke: $primaryHeaderColor !important; + } + + .p-menu { + color: $primaryTextColor !important; + + .p-menuitem-link .p-menuitem-text, + .p-menuitem-link .p-menuitem-icon { + color: $primaryTextColor !important; + } + + .p-menuitem-link:focus { + box-shadow: none !important; + } + + .p-menuitem-link:hover { + background-color: $secondaryBackgroundColor !important; + $border-radius: 20px; + border-radius: $border-radius 0px 0px $border-radius; + + .p-menuitem-text, + .p-menuitem-icon { + color: $primaryHeaderColor !important; + } + } + } + + .p-menu-overlay { + background-color: $primaryBackgroundColor !important; + color: $primaryTextColor !important; + border-top: 2px solid $primaryHeaderColor !important; + + .p-menuitem-link:hover { + background-color: $primaryBackgroundColor !important; + .p-menuitem-text, + .p-menuitem-icon { + color: $primaryHeaderColor !important; + } + } + } + + p-dropdown { + .p-dropdown { + background-color: $primaryBackgroundColor !important; + border-color: $primaryTextColor !important; + color: $primaryTextColor !important; + + span { + color: $primaryTextColor; + } + + .p-dropdown-panel { + background-color: $primaryBackgroundColor !important; + + .p-dropdown-items .p-dropdown-item:not(.p-highlight):not(.p-disabled):hover { + background-color: $primaryBackgroundColor !important; + color: $primaryHeaderColor !important; + + span { + color: $primaryHeaderColor !important; + } + } + + .p-dropdown-items .p-dropdown-item.p-highlight { + background-color: $primaryBackgroundColor !important; + color: $primaryHeaderColor !important; + + span { + color: $primaryHeaderColor !important; + } + } + } + } + } + + p-table { + background-color: $primaryBackgroundColor; + color: $primaryTextColor !important; + + .table-caption { + .table-caption-text { + } + + .table-caption-search-wrapper { + .table-caption-search { + height: 30px !important; + + .table-caption-search-icon { + } + + .table-caption-search-input { + height: 100% !important; + + &:focus { + outline-color: $primaryHeaderColor; + } + } + } + } + + .table-caption-btn-wrapper { + height: 30px !important; + } + } + + .table-edit-input { + width: 100% !important; + } + } + + p-checkbox { + .p-checkbox .p-checkbox-box { + background: $primaryBackgroundColor !important; + background-color: $primaryBackgroundColor !important; + } + + .p-checkbox .p-checkbox-box.p-highlight { + background: $primaryBackgroundColor !important; + background-color: $primaryBackgroundColor !important; + border-color: $primaryTextColor !important; + box-shadow: none !important; + } + + .p-checkbox .p-checkbox-box .p-checkbox-icon { + color: $primaryTextColor !important; + } + + .p-checkbox:not(.p-checkbox-disabled) .p-checkbox-box.p-focus, + .p-checkbox:not(.p-checkbox-disabled) .p-checkbox-box:hover { + border-color: $primaryHeaderColor !important; + box-shadow: none !important; + + .p-checkbox-icon { + color: $primaryHeaderColor !important; + } + } + } + + p-dialog, + p-confirmdialog, + p-dynamicdialog { + .p-dialog.p-confirm-dialog .p-confirm-dialog-message { + margin-left: 0px !important; + } + + .p-dialog { + background-color: $primaryBackgroundColor !important; + + .p-dialog-header { + background-color: $secondaryBackgroundColor !important; + color: $primaryTextColor !important; + } + + .p-dialog-content, + .p-dialog-footer { + background-color: $primaryBackgroundColor !important; + color: $primaryTextColor !important; + } + } + } + + input, + .p-password { + &:focus { + box-shadow: none !important; + } + + &:hover, + &:active, + &:enabled:focus { + border-color: $primaryHeaderColor !important; + } + } + + .btn-wrapper { + display: flex !important; + align-items: center !important; + } + + .btn { + background-color: $primaryHeaderColor; + color: $primaryTextColor; + border: 0; + + &:hover, + &:enabled:hover { + background-color: $primaryHeaderColor; + color: $primaryTextColor; + border: 0; + } + } + + .icon-btn { + background-color: transparent !important; + color: $primaryTextColor !important; + border: 0 !important; + + .pi { + font-size: 1.275rem !important; + } + } + + .text-btn { + background-color: transparent !important; + color: $primaryTextColor !important; + border: 0 !important; + padding: 0px !important; + + &:hover { + background-color: transparent !important; + color: $primaryHeaderColor !important; + border: 0; + } + } + + .icon-btn-without-hover { + &:hover { + background-color: transparent !important; + color: $primaryTextColor !important; + border: 0 !important; + } + } + + .icon-btn { + &:hover { + background-color: transparent !important; + color: $primaryHeaderColor !important; + border: 0; + } + } + + .danger-icon-btn { + background-color: transparent !important; + color: $primaryTextColor !important; + border: 0 !important; + + &:hover { + background-color: transparent !important; + color: $primaryErrorColor !important; + border: 0; + } + + .pi { + font-size: 1.275rem !important; + } + } + + .danger-btn { + background-color: $primaryErrorColor !important; + color: $primaryErrorColor !important; + border: 0 !important; + + &:hover { + background-color: $primaryErrorColor !important; + color: $primaryTextColor !important; + border: 0; + } + + .pi { + font-size: 1.275rem !important; + } + } + + .p-datatable .p-sortable-column.p-highlight, + .p-datatable .p-sortable-column.p-highlight .p-sortable-column-icon { + color: $primaryHeaderColor !important; + } + + .p-dropdown:not(.p-disabled):hover, + .p-dropdown:not(.p-disabled).p-focus, + .p-link:focus { + border-color: $primaryHeaderColor !important; + box-shadow: none !important; + } + + .p-paginator .p-paginator-pages .p-paginator-page.p-highlight { + background: transparent !important; + background-color: transparent !important; + color: $primaryHeaderColor !important; + } + + .p-paginator .p-paginator-pages .p-paginator-page:not(.p-highlight):hover, + .p-paginator .p-paginator-first:not(.p-disabled):not(.p-highlight):hover, + .p-paginator .p-paginator-prev:not(.p-disabled):not(.p-highlight):hover, + .p-paginator .p-paginator-next:not(.p-disabled):not(.p-highlight):hover, + .p-paginator .p-paginator-last:not(.p-disabled):not(.p-highlight):hover { + background-color: $primaryBackgroundColor !important; + color: $primaryHeaderColor !important; + } +} diff --git a/kdb-web/src/test.ts b/kdb-web/src/test.ts new file mode 100644 index 0000000000..c04c876075 --- /dev/null +++ b/kdb-web/src/test.ts @@ -0,0 +1,26 @@ +// This file is required by karma.conf.js and loads recursively all the .spec and framework files + +import 'zone.js/testing'; +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; + +declare const require: { + context(path: string, deep?: boolean, filter?: RegExp): { + (id: string): T; + keys(): string[]; + }; +}; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting(), +); + +// Then we find all the tests. +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().forEach(context); diff --git a/kdb-web/tsconfig.app.json b/kdb-web/tsconfig.app.json new file mode 100644 index 0000000000..82d91dc4a4 --- /dev/null +++ b/kdb-web/tsconfig.app.json @@ -0,0 +1,15 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/app", + "types": [] + }, + "files": [ + "src/main.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.d.ts" + ] +} diff --git a/kdb-web/tsconfig.json b/kdb-web/tsconfig.json new file mode 100644 index 0000000000..ff06eae10c --- /dev/null +++ b/kdb-web/tsconfig.json @@ -0,0 +1,32 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "compileOnSave": false, + "compilerOptions": { + "baseUrl": "./", + "outDir": "./dist/out-tsc", + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "sourceMap": true, + "declaration": false, + "downlevelIteration": true, + "experimentalDecorators": true, + "moduleResolution": "node", + "importHelpers": true, + "target": "es2020", + "module": "es2020", + "lib": [ + "es2020", + "dom" + ] + }, + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/kdb-web/tsconfig.spec.json b/kdb-web/tsconfig.spec.json new file mode 100644 index 0000000000..092345b02e --- /dev/null +++ b/kdb-web/tsconfig.spec.json @@ -0,0 +1,18 @@ +/* To learn more about this file see: https://angular.io/config/tsconfig. */ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./out-tsc/spec", + "types": [ + "jasmine" + ] + }, + "files": [ + "src/test.ts", + "src/polyfills.ts" + ], + "include": [ + "src/**/*.spec.ts", + "src/**/*.d.ts" + ] +} diff --git a/kdb-web/update-version.ts b/kdb-web/update-version.ts new file mode 100644 index 0000000000..9131c49960 --- /dev/null +++ b/kdb-web/update-version.ts @@ -0,0 +1,54 @@ +import { Appsettings } from 'src/app/models/config/appsettings'; +import { SoftwareVersion } from './src/app/models/config/software-version'; + +const jsonFilePath = './src/assets/config.json'; + +function Main(): void { + getVersion() + .then(version => { + setVersion(version); + }) + .catch(err => { + throw err; + }); +} + +async function getVersion(): Promise { + const util = require('util'); + const exec = util.promisify(require('child_process').exec); + + let major = '0'; + let minor = '0'; + let micro = '0'; + + const branch: string = (await exec('git rev-parse --abbrev-ref HEAD')).stdout.toString().trim(); + if (branch.includes('.')) { + const versions = branch.split('.'); + if (versions.length > 0) { + major = versions[0]; + } + + if (versions.length > 1) { + minor = versions[1]; + } + + if (versions.length > 2) { + micro = versions[2]; + } + } + return new SoftwareVersion(major, minor, micro); +} + +async function setVersion(version: SoftwareVersion) { + var fs = require('fs'); + fs.readFile(jsonFilePath, 'utf8', (err: Error, data: string) => { + if (err) { + throw err; + } + const settings: Appsettings = JSON.parse(data); + settings.WebVersion = version; + fs.writeFile(jsonFilePath, JSON.stringify(settings, null, 4), 'utf8', () => {}); + }); +} + +Main(); From 651482a1b98ee09bc07cd9164aa075a4fd88a110 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sun, 16 Oct 2022 01:55:20 +0200 Subject: [PATCH 023/102] Added api connection check #70 --- kdb-bot/src/bot/bot.json | 4 +- kdb-bot/src/bot_api/api.py | 25 +++- kdb-web/package-lock.json | 107 ++++++++++++++---- kdb-web/package.json | 2 + kdb-web/src/app/app.component.ts | 3 + kdb-web/src/app/app.module.ts | 4 +- .../services/socket/socket.service.spec.ts | 16 +++ .../src/app/services/socket/socket.service.ts | 71 ++++++++++++ kdb-web/src/assets/config.json | 2 +- 9 files changed, 210 insertions(+), 24 deletions(-) create mode 100644 kdb-web/src/app/services/socket/socket.service.spec.ts create mode 100644 kdb-web/src/app/services/socket/socket.service.ts diff --git a/kdb-bot/src/bot/bot.json b/kdb-bot/src/bot/bot.json index 799d3fe8fd..985c978b2c 100644 --- a/kdb-bot/src/bot/bot.json +++ b/kdb-bot/src/bot/bot.json @@ -24,7 +24,9 @@ "Flask-Classful==0.14.2", "Flask-Cors==3.0.10", "PyJWT==2.5.0", - "waitress==2.1.2" + "waitress==2.1.2", + "Flask-SocketIO==5.3.1", + "eventlet==0.33.1" ], "DevDependencies": [ "cpl-cli==2022.10.0" diff --git a/kdb-bot/src/bot_api/api.py b/kdb-bot/src/bot_api/api.py index 7930b861ce..b79a12d20f 100644 --- a/kdb-bot/src/bot_api/api.py +++ b/kdb-bot/src/bot_api/api.py @@ -3,11 +3,15 @@ import sys import uuid from functools import partial +import eventlet from cpl_core.dependency_injection import ServiceProviderABC +from eventlet import wsgi from flask import Flask, request, jsonify, Response, make_response from flask_cors import CORS +from flask_socketio import SocketIO from bot_api.configuration.api_settings import ApiSettings +from bot_api.configuration.frontend_settings import FrontendSettings from bot_api.exception.service_exception import ServiceException from bot_api.logging.api_logger import ApiLogger from bot_api.model.error_dto import ErrorDTO @@ -21,6 +25,7 @@ class Api(Flask): logger: ApiLogger, services: ServiceProviderABC, api_settings: ApiSettings, + frontend_settings: FrontendSettings, *args, **kwargs ): if not args: @@ -39,6 +44,11 @@ class Api(Flask): exc_class, code = self._get_exc_class_and_code(Exception) self.error_handler_spec[None][code][exc_class] = self.handle_exception + # websockets + self._socketio = SocketIO(self, cors_allowed_origins='*') + self._socketio.on_event('connect', self.on_connect) + self._socketio.on_event('disconnect', self.on_disconnect) + def _register_routes(self): for path, f in Route.registered_routes.items(): route = f[0] @@ -76,6 +86,17 @@ class Api(Flask): def start(self): self._logger.info(__name__, f'Starting API {self._apt_settings.host}:{self._apt_settings.port}') self._register_routes() - from waitress import serve + # from waitress import serve # https://docs.pylonsproject.org/projects/waitress/en/stable/arguments.html - serve(self, host=self._apt_settings.host, port=self._apt_settings.port, threads=10, connection_limit=1000, channel_timeout=10) + # serve(self, host=self._apt_settings.host, port=self._apt_settings.port, threads=10, connection_limit=1000, channel_timeout=10) + wsgi.server( + eventlet.listen((self._apt_settings.host, self._apt_settings.port)), + self, + log_output=False + ) + + def on_connect(self): + self._logger.info(__name__, f'Client connected') + + def on_disconnect(self): + self._logger.info(__name__, f'Client disconnected') diff --git a/kdb-web/package-lock.json b/kdb-web/package-lock.json index 46d080cf42..273efa031e 100644 --- a/kdb-web/package-lock.json +++ b/kdb-web/package-lock.json @@ -1,12 +1,12 @@ { "name": "kdb-web", - "version": "0.0.0", + "version": "0.3.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "kdb-web", - "version": "0.0.0", + "version": "0.3.0", "dependencies": { "@angular/animations": "^14.0.0", "@angular/common": "^14.0.0", @@ -20,9 +20,11 @@ "@microsoft/signalr": "^6.0.9", "@ngx-translate/core": "^14.0.0", "@ngx-translate/http-loader": "^7.0.0", + "@types/socket.io-client": "^3.0.0", "primeicons": "^6.0.1", "primeng": "^14.1.2", "rxjs": "~7.5.0", + "socket.io-client": "^4.5.3", "tslib": "^2.3.0", "zone.js": "~0.11.4" }, @@ -3080,8 +3082,7 @@ "node_modules/@socket.io/component-emitter": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", - "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", - "dev": true + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" }, "node_modules/@tootallnate/once": { "version": "1.1.2", @@ -3267,6 +3268,15 @@ "@types/node": "*" } }, + "node_modules/@types/socket.io-client": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-3.0.0.tgz", + "integrity": "sha512-s+IPvFoEIjKA3RdJz/Z2dGR4gLgysKi8owcnrVwNjgvc01Lk68LJDDsG2GRqegFITcxmvCMYM7bhMpwEMlHmDg==", + "deprecated": "This is a stub types definition. socket.io-client provides its own type definitions, so you do not need this installed.", + "dependencies": { + "socket.io-client": "*" + } + }, "node_modules/@types/sockjs": { "version": "0.3.33", "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", @@ -4902,7 +4912,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -5194,11 +5203,22 @@ "node": ">=10.0.0" } }, + "node_modules/engine.io-client": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.2.3.tgz", + "integrity": "sha512-aXPtgF1JS3RuuKcpSrBtimSjYvrbhKW9froICH4s0F3XQWLxsKNxqzG39nnvQZQnva4CMvUK63T7shevxRyYHw==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.2.3", + "xmlhttprequest-ssl": "~2.0.0" + } + }, "node_modules/engine.io-parser": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==", - "dev": true, "engines": { "node": ">=10.0.0" } @@ -8305,8 +8325,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/multicast-dns": { "version": "7.2.5", @@ -11018,11 +11037,24 @@ "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==", "dev": true }, + "node_modules/socket.io-client": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.3.tgz", + "integrity": "sha512-I/hqDYpQ6JKwtJOf5ikM+Qz+YujZPMEl6qBLhxiP0nX+TfXKhW4KZZG8lamrD6Y5ngjmYHreESVasVCgi5Kl3A==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.2.3", + "socket.io-parser": "~4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/socket.io-parser": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", - "dev": true, "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" @@ -12416,7 +12448,6 @@ "version": "8.2.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", - "dev": true, "engines": { "node": ">=10.0.0" }, @@ -12433,6 +12464,14 @@ } } }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -14566,8 +14605,7 @@ "@socket.io/component-emitter": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", - "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", - "dev": true + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" }, "@tootallnate/once": { "version": "1.1.2", @@ -14750,6 +14788,14 @@ "@types/node": "*" } }, + "@types/socket.io-client": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/socket.io-client/-/socket.io-client-3.0.0.tgz", + "integrity": "sha512-s+IPvFoEIjKA3RdJz/Z2dGR4gLgysKi8owcnrVwNjgvc01Lk68LJDDsG2GRqegFITcxmvCMYM7bhMpwEMlHmDg==", + "requires": { + "socket.io-client": "*" + } + }, "@types/sockjs": { "version": "0.3.33", "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz", @@ -16001,7 +16047,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "requires": { "ms": "2.1.2" } @@ -16223,11 +16268,22 @@ "ws": "~8.2.3" } }, + "engine.io-client": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.2.3.tgz", + "integrity": "sha512-aXPtgF1JS3RuuKcpSrBtimSjYvrbhKW9froICH4s0F3XQWLxsKNxqzG39nnvQZQnva4CMvUK63T7shevxRyYHw==", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.2.3", + "xmlhttprequest-ssl": "~2.0.0" + } + }, "engine.io-parser": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", - "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==", - "dev": true + "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==" }, "enhanced-resolve": { "version": "5.10.0", @@ -18475,8 +18531,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "multicast-dns": { "version": "7.2.5", @@ -20407,11 +20462,21 @@ "integrity": "sha512-W4N+o69rkMEGVuk2D/cvca3uYsvGlMwsySWV447y99gUPghxq42BxqLNMndb+a1mm/5/7NeXVQS7RLa2XyXvYg==", "dev": true }, + "socket.io-client": { + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.3.tgz", + "integrity": "sha512-I/hqDYpQ6JKwtJOf5ikM+Qz+YujZPMEl6qBLhxiP0nX+TfXKhW4KZZG8lamrD6Y5ngjmYHreESVasVCgi5Kl3A==", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.2.3", + "socket.io-parser": "~4.2.0" + } + }, "socket.io-parser": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", - "dev": true, "requires": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" @@ -21424,9 +21489,13 @@ "version": "8.2.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", - "dev": true, "requires": {} }, + "xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==" + }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/kdb-web/package.json b/kdb-web/package.json index 5d0195d078..e38246960c 100644 --- a/kdb-web/package.json +++ b/kdb-web/package.json @@ -25,9 +25,11 @@ "@microsoft/signalr": "^6.0.9", "@ngx-translate/core": "^14.0.0", "@ngx-translate/http-loader": "^7.0.0", + "@types/socket.io-client": "^3.0.0", "primeicons": "^6.0.1", "primeng": "^14.1.2", "rxjs": "~7.5.0", + "socket.io-client": "^4.5.3", "tslib": "^2.3.0", "zone.js": "~0.11.4" }, diff --git a/kdb-web/src/app/app.component.ts b/kdb-web/src/app/app.component.ts index 90758e7d54..6d8046ff17 100644 --- a/kdb-web/src/app/app.component.ts +++ b/kdb-web/src/app/app.component.ts @@ -1,5 +1,6 @@ import { Component, OnInit } from '@angular/core'; import { AuthService } from './services/auth/auth.service'; +import { SocketService } from './services/socket/socket.service'; import { ThemeService } from './services/theme/theme.service'; @Component({ @@ -12,9 +13,11 @@ export class AppComponent implements OnInit { constructor( public authService: AuthService, public themeService: ThemeService, + private socket: SocketService ) { } ngOnInit(): void { + this.socket.startSocket(); this.themeService.loadTheme(); this.themeService.loadMenu(); } diff --git a/kdb-web/src/app/app.module.ts b/kdb-web/src/app/app.module.ts index c8ae9aed0a..bda8098f9d 100644 --- a/kdb-web/src/app/app.module.ts +++ b/kdb-web/src/app/app.module.ts @@ -9,6 +9,7 @@ import { ConfirmationService, MessageService } from 'primeng/api'; import { DialogService } from 'primeng/dynamicdialog'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; +import { NotFoundComponent } from './components/error/not-found/not-found.component'; import { FooterComponent } from './components/footer/footer.component'; import { HeaderComponent } from './components/header/header.component'; import { SidebarComponent } from './components/sidebar/sidebar.component'; @@ -16,7 +17,8 @@ import { SpinnerComponent } from './components/spinner/spinner.component'; import { SharedModule } from './modules/shared/shared.module'; import { ErrorHandlerService } from './services/error-handler/error-handler.service'; import { SettingsService } from './services/settings/settings.service'; -import { NotFoundComponent } from './components/error/not-found/not-found.component'; + + @NgModule({ declarations: [ diff --git a/kdb-web/src/app/services/socket/socket.service.spec.ts b/kdb-web/src/app/services/socket/socket.service.spec.ts new file mode 100644 index 0000000000..7ceaf59829 --- /dev/null +++ b/kdb-web/src/app/services/socket/socket.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { SocketService } from './socket.service'; + +describe('SocketService', () => { + let service: SocketService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(SocketService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/services/socket/socket.service.ts b/kdb-web/src/app/services/socket/socket.service.ts new file mode 100644 index 0000000000..4493587408 --- /dev/null +++ b/kdb-web/src/app/services/socket/socket.service.ts @@ -0,0 +1,71 @@ +import { HttpClient } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { ToastOptions } from 'src/app/models/utils/toast-options'; +import { SettingsService } from '../settings/settings.service'; +import { SpinnerService } from '../spinner/spinner.service'; +import { ToastService } from '../toast/toast.service'; +import io from "socket.io-client"; +import { MessageService } from 'primeng/api'; + +@Injectable({ + providedIn: 'root' +}) +export class SocketService { + private socket: any; + disconnected = false; + + constructor( + private settingsService: SettingsService, + private toastService: ToastService, + private spinnerService: SpinnerService, + private messageService: MessageService, + ) { + this.socket = io(`${settingsService.getApiURL()}`) + } + + startSocket() { + this.socket.on('connect', () => { + if (this.disconnected) { + if (this.spinnerService.showSpinnerState) { + this.spinnerService.hideSpinner(); + const options: ToastOptions = { + closable: false + }; + this.messageService.clear(); + this.toastService.info("Server verbunden", "Die Verbindung zum Server konnte hergestellt werden.", options); + } + } + + this.disconnected = false; + console.log('Connected!') + }); + + this.socket.on('connect_error', (err: Error) => { + if (this.disconnected) { + this.spinnerService.showSpinner(); + return; + } + + this.disconnected = true; + + const options: ToastOptions = { + sticky: true, + closable: false + }; + this.messageService.clear(); + this.toastService.error("Server nicht erreichbar", "Die Verbindung zum Server konnte nicht hergestellt werden!\nLaden Sie die Seite neu.", options); + console.error(err.toString()); + }); + + this.socket.on('disconnect', () => { + console.log('Disconnected!'); + const options: ToastOptions = { + sticky: true, + closable: false + }; + this.spinnerService.showSpinner(); + this.messageService.clear(); + this.toastService.error("Verbindung unterbrochen", "Die Verbindung zum Server konnte nicht hergestellt werden!\nLaden Sie die Seite neu.", options); + }); + } +} diff --git a/kdb-web/src/assets/config.json b/kdb-web/src/assets/config.json index 905b2d2f3c..f135341693 100644 --- a/kdb-web/src/assets/config.json +++ b/kdb-web/src/assets/config.json @@ -2,7 +2,7 @@ "ApiURL": "http://localhost:5000", "WebVersion": { "Major": "0", - "Minor": "3", + "Minor": "0", "Micro": "0" }, "Themes": [ From 3fe8e1503c858b5193aac816749490d15388a528 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sun, 16 Oct 2022 10:11:21 +0200 Subject: [PATCH 024/102] Added authorize check to controller #70 --- kdb-bot/src/bot/main.py | 2 + kdb-bot/src/bot_api/abc/auth_service_abc.py | 10 +++++ kdb-bot/src/bot_api/app_api_extension.py | 26 +++++++++++++ .../src/bot_api/controller/auth_controller.py | 10 +++++ .../src/bot_api/controller/gui_controller.py | 2 + kdb-bot/src/bot_api/route/route.py | 39 +++++++++++++++++++ kdb-bot/src/bot_api/service/auth_service.py | 34 +++++++++++----- 7 files changed, 114 insertions(+), 9 deletions(-) create mode 100644 kdb-bot/src/bot_api/app_api_extension.py diff --git a/kdb-bot/src/bot/main.py b/kdb-bot/src/bot/main.py index d2bbdb5a5e..9747634bb7 100644 --- a/kdb-bot/src/bot/main.py +++ b/kdb-bot/src/bot/main.py @@ -11,6 +11,7 @@ from bot.startup_discord_extension import StartupDiscordExtension from bot.startup_migration_extension import StartupMigrationExtension from bot.startup_module_extension import StartupModuleExtension from bot.startup_settings_extension import StartupSettingsExtension +from bot_api.app_api_extension import AppApiExtension from modules.boot_log.boot_log_extension import BootLogExtension from modules.database.database_extension import DatabaseExtension @@ -29,6 +30,7 @@ class Program: .use_extension(StartupMigrationExtension) \ .use_extension(BootLogExtension) \ .use_extension(DatabaseExtension) \ + .use_extension(AppApiExtension) \ .use_startup(Startup) self.app: Application = await app_builder.build_async() await self.app.run_async() diff --git a/kdb-bot/src/bot_api/abc/auth_service_abc.py b/kdb-bot/src/bot_api/abc/auth_service_abc.py index 28d1374911..3a006a0dcf 100644 --- a/kdb-bot/src/bot_api/abc/auth_service_abc.py +++ b/kdb-bot/src/bot_api/abc/auth_service_abc.py @@ -9,6 +9,7 @@ from bot_api.model.email_string_dto import EMailStringDTO from bot_api.model.reset_password_dto import ResetPasswordDTO from bot_api.model.token_dto import TokenDTO from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO +from bot_data.model.auth_user import AuthUser class AuthServiceABC(ABC): @@ -16,6 +17,12 @@ class AuthServiceABC(ABC): @abstractmethod def __init__(self): pass + @abstractmethod + def generate_token(self, user: AuthUser) -> str: pass + + @abstractmethod + def decode_token(self, token: str) -> dict: pass + @abstractmethod async def get_all_auth_users_async(self) -> List[AuthUserDTO]: pass @@ -43,6 +50,9 @@ class AuthServiceABC(ABC): @abstractmethod async def delete_auth_user_async(self, user_dto: AuthUserDTO): pass + @abstractmethod + async def verify_login(self, token_str: str) -> bool: pass + @abstractmethod async def login_async(self, user_dto: AuthUserDTO) -> TokenDTO: pass diff --git a/kdb-bot/src/bot_api/app_api_extension.py b/kdb-bot/src/bot_api/app_api_extension.py new file mode 100644 index 0000000000..c0b5fd12cb --- /dev/null +++ b/kdb-bot/src/bot_api/app_api_extension.py @@ -0,0 +1,26 @@ +from cpl_core.application import ApplicationExtensionABC +from cpl_core.configuration import ConfigurationABC +from cpl_core.dependency_injection import ServiceProviderABC + +from bot_api.abc.auth_service_abc import AuthServiceABC +from bot_api.configuration.authentication_settings import AuthenticationSettings +from bot_api.route.route import Route +from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum +from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings +from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC + + +class AppApiExtension(ApplicationExtensionABC): + + def __init__(self): + ApplicationExtensionABC.__init__(self) + + async def run(self, config: ConfigurationABC, services: ServiceProviderABC): + feature_flags: FeatureFlagsSettings = config.get_configuration(FeatureFlagsSettings) + if not feature_flags.get_flag(FeatureFlagsEnum.api_module): + return + + auth_settings: AuthenticationSettings = config.get_configuration(AuthenticationSettings) + auth_users: AuthUserRepositoryABC = services.get_service(AuthUserRepositoryABC) + auth: AuthServiceABC = services.get_service(AuthServiceABC) + Route.init_authorize(auth_users, auth) diff --git a/kdb-bot/src/bot_api/controller/auth_controller.py b/kdb-bot/src/bot_api/controller/auth_controller.py index c5e10d1c6c..ee64bf656b 100644 --- a/kdb-bot/src/bot_api/controller/auth_controller.py +++ b/kdb-bot/src/bot_api/controller/auth_controller.py @@ -39,11 +39,13 @@ class AuthController: self._auth_service = auth_service @Route.get(f'{BasePath}/users') + @Route.authorize async def get_all_users(self) -> Response: result = await self._auth_service.get_all_auth_users_async() return jsonify(result.select(lambda x: x.to_dict())) @Route.post(f'{BasePath}/users/get/filtered') + @Route.authorize async def get_filtered_users(self) -> Response: dto: AuthUserSelectCriteria = JSONProcessor.process(AuthUserSelectCriteria, request.get_json(force=True, silent=True)) result = await self._auth_service.get_filtered_auth_users_async(dto) @@ -51,11 +53,13 @@ class AuthController: return jsonify(result.to_dict()) @Route.get(f'{BasePath}/users/get/') + @Route.authorize async def get_user_from_email(self, email: str) -> Response: result = await self._auth_service.get_auth_user_by_email_async(email) return jsonify(result.to_dict()) @Route.get(f'{BasePath}/users/find/') + @Route.authorize async def find_user_from_email(self, email: str) -> Response: result = await self._auth_service.find_auth_user_by_email_async(email) return jsonify(result.to_dict()) @@ -83,36 +87,42 @@ class AuthController: return '', 200 @Route.post(f'{BasePath}/update-user') + @Route.authorize async def update_user(self): dto: UpdateAuthUserDTO = JSONProcessor.process(UpdateAuthUserDTO, request.get_json(force=True, silent=True)) await self._auth_service.update_user_async(dto) return '', 200 @Route.post(f'{BasePath}/update-user-as-admin') + @Route.authorize async def update_user_as_admin(self): dto: UpdateAuthUserDTO = JSONProcessor.process(UpdateAuthUserDTO, request.get_json(force=True, silent=True)) await self._auth_service.update_user_async(dto) return '', 200 @Route.post(f'{BasePath}/refresh') + @Route.authorize async def refresh(self) -> Response: dto: TokenDTO = JSONProcessor.process(TokenDTO, request.get_json(force=True, silent=True)) result = await self._auth_service.refresh_async(dto) return jsonify(result.to_dict()) @Route.post(f'{BasePath}/revoke') + @Route.authorize async def revoke(self): dto: TokenDTO = JSONProcessor.process(TokenDTO, request.get_json(force=True, silent=True)) await self._auth_service.revoke_async(dto) return '', 200 @Route.post(f'{BasePath}/delete-user') + @Route.authorize async def delete_user(self): dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True)) await self._auth_service.delete_auth_user_async(dto) return '', 200 @Route.post(f'{BasePath}/delete-user-by-mail/') + @Route.authorize async def delete_user_by_mail(self, email: str): await self._auth_service.delete_auth_user_by_email_async(email) return '', 200 diff --git a/kdb-bot/src/bot_api/controller/gui_controller.py b/kdb-bot/src/bot_api/controller/gui_controller.py index a2fa883aab..dccc2099b6 100644 --- a/kdb-bot/src/bot_api/controller/gui_controller.py +++ b/kdb-bot/src/bot_api/controller/gui_controller.py @@ -40,6 +40,7 @@ class GuiController: return VersionDTO(version.major, version.minor, version.micro).to_dict() @Route.get(f'{BasePath}/settings') + @Route.authorize async def settings(self): # TODO: Authentication import bot_api @@ -61,6 +62,7 @@ class GuiController: ).to_dict() @Route.get(f'{BasePath}/send-test-mail/') + @Route.authorize async def send_test_mail(self, email: str): # TODO: Authentication mail = EMail() diff --git a/kdb-bot/src/bot_api/route/route.py b/kdb-bot/src/bot_api/route/route.py index 74fbbc6724..429b24a367 100644 --- a/kdb-bot/src/bot_api/route/route.py +++ b/kdb-bot/src/bot_api/route/route.py @@ -1,9 +1,48 @@ +from functools import wraps +from typing import Optional + +from flask import request from flask_cors import cross_origin +from bot_api.abc.auth_service_abc import AuthServiceABC +from bot_api.exception.service_error_code_enum import ServiceErrorCode +from bot_api.exception.service_exception import ServiceException +from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC + class Route: registered_routes = {} + _auth_users: Optional[AuthUserRepositoryABC] = None + _auth: Optional[AuthServiceABC] = None + + @classmethod + def init_authorize(cls, auth_users: AuthUserRepositoryABC, auth: AuthServiceABC): + cls._auth_users = auth_users + cls._auth = auth + + @classmethod + def authorize(cls, f): + @wraps(f) + async def decorator(*args, **kwargs): + token = None + if 'Authorization' in request.headers: + bearer = request.headers.get('Authorization') + token = bearer.split()[1] + + if not token: + raise ServiceException(ServiceErrorCode.InvalidData, f'Token not set') + + if cls._auth_users is None or cls._auth is None: + raise ServiceException(ServiceErrorCode.InvalidDependencies, f'Authorize is not initialized') + + if not cls._auth.verify_login(token): + raise ServiceException(ServiceErrorCode.InvalidUser, f'Token expired') + + return await f(*args, **kwargs) + + return decorator + @classmethod def route(cls, path=None, **kwargs): # simple decorator for class based views diff --git a/kdb-bot/src/bot_api/service/auth_service.py b/kdb-bot/src/bot_api/service/auth_service.py index ede6f15f18..0a78a9c448 100644 --- a/kdb-bot/src/bot_api/service/auth_service.py +++ b/kdb-bot/src/bot_api/service/auth_service.py @@ -70,7 +70,7 @@ class AuthService(AuthServiceABC): return False - def _generate_token(self, user: AuthUser) -> str: + def generate_token(self, user: AuthUser) -> str: token = jwt.encode( payload={ 'user_id': user.id, @@ -85,7 +85,7 @@ class AuthService(AuthServiceABC): return token - def _decode_token(self, token: str) -> dict: + def decode_token(self, token: str) -> dict: return jwt.decode( token, key=self._auth_settings.secret_key, @@ -292,6 +292,21 @@ class AuthService(AuthServiceABC): self._logger.error(__name__, f'Cannot delete user', e) raise ServiceException(ServiceErrorCode.UnableToDelete, f'Cannot delete user by mail {user_dto.email}') + def verify_login(self, token_str: str) -> bool: + try: + token = self.decode_token(token_str) + if token is None or 'email' not in token: + raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid') + + user = self._auth_users.find_auth_user_by_email(token['email']) + if user is None: + raise ServiceException(ServiceErrorCode.InvalidData, 'Token expired') + except Exception as e: + self._logger.error(__name__, f'Refreshing token failed', e) + return False + + return True + async def login_async(self, user_dto: AuthUser) -> TokenDTO: if user_dto is None: raise ServiceException(ServiceErrorCode.InvalidData, 'User not set') @@ -304,7 +319,7 @@ class AuthService(AuthServiceABC): if db_user.password != user_dto.password: raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong password') - token = self._generate_token(db_user) + token = self.generate_token(db_user) refresh_token = self._create_and_save_refresh_token(db_user) if db_user.forgot_password_id is not None: db_user.forgot_password_id = None @@ -316,16 +331,16 @@ class AuthService(AuthServiceABC): if token_dto is None: raise ServiceException(ServiceErrorCode.InvalidData, f'Token not set') - token = self._decode_token(token_dto.token) - if token is None or 'email' not in token: - raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid') - try: + token = self.decode_token(token_dto.token) + if token is None or 'email' not in token: + raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid') + user = self._auth_users.get_auth_user_by_email(token['email']) if user is None or user.refresh_token != token_dto.refresh_token or user.refresh_token_expire_time <= datetime.now(): raise ServiceException(ServiceErrorCode.InvalidData, 'Token expired') - return TokenDTO(self._generate_token(user), self._create_and_save_refresh_token(user)) + return TokenDTO(self.generate_token(user), self._create_and_save_refresh_token(user)) except Exception as e: self._logger.error(__name__, f'Refreshing token failed', e) return TokenDTO('', '') @@ -334,8 +349,9 @@ class AuthService(AuthServiceABC): if token_dto is None or token_dto.token is None or token_dto.refresh_token is None: raise ServiceException(ServiceErrorCode.InvalidData, 'Token not set') - token = self._decode_token(token_dto.token) try: + token = self.decode_token(token_dto.token) + user = self._auth_users.get_auth_user_by_email(token['email']) if user is None or user.refresh_token != token_dto.refresh_token or user.refresh_token_expire_time <= datetime.now(): raise ServiceException(ServiceErrorCode.InvalidData, 'Token expired') From ba881aefa8d91ac96dccfc595a71be2a94046db4 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sun, 16 Oct 2022 12:06:18 +0200 Subject: [PATCH 025/102] Added verify-login #70 --- .../src/bot_api/controller/auth_controller.py | 16 +++- .../exception/service_error_code_enum.py | 4 + kdb-bot/src/bot_api/route/route.py | 17 +++-- .../models/error/service-error-code.enum.ts | 3 +- .../auth-user/auth-user.component.ts | 2 +- kdb-web/src/app/services/auth/auth.service.ts | 75 ++++++++++--------- .../error-handler/error-handler.service.ts | 13 +++- .../app/services/settings/settings.service.ts | 2 +- .../src/app/services/theme/theme.service.ts | 8 +- 9 files changed, 93 insertions(+), 47 deletions(-) diff --git a/kdb-bot/src/bot_api/controller/auth_controller.py b/kdb-bot/src/bot_api/controller/auth_controller.py index ee64bf656b..5342df92c6 100644 --- a/kdb-bot/src/bot_api/controller/auth_controller.py +++ b/kdb-bot/src/bot_api/controller/auth_controller.py @@ -6,6 +6,8 @@ from flask import request, jsonify, Response from bot_api.abc.auth_service_abc import AuthServiceABC from bot_api.api import Api +from bot_api.exception.service_error_code_enum import ServiceErrorCode +from bot_api.exception.service_exception import ServiceException from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria from bot_api.json_processor import JSONProcessor from bot_api.logging.api_logger import ApiLogger @@ -76,6 +78,19 @@ class AuthController: result = await self._auth_service.login_async(dto) return jsonify(result.to_dict()) + @Route.get(f'{BasePath}/verify-login') + async def verify_login(self): + token = None + result = False + if 'Authorization' in request.headers: + bearer = request.headers.get('Authorization') + token = bearer.split()[1] + + if token is not None: + result = self._auth_service.verify_login(token) + + return jsonify(result) + @Route.post(f'{BasePath}/forgot-password/') async def forgot_password(self, email: str): await self._auth_service.forgot_password_async(email) @@ -108,7 +123,6 @@ class AuthController: return jsonify(result.to_dict()) @Route.post(f'{BasePath}/revoke') - @Route.authorize async def revoke(self): dto: TokenDTO = JSONProcessor.process(TokenDTO, request.get_json(force=True, silent=True)) await self._auth_service.revoke_async(dto) diff --git a/kdb-bot/src/bot_api/exception/service_error_code_enum.py b/kdb-bot/src/bot_api/exception/service_error_code_enum.py index 24da48ed24..7b19aeb18c 100644 --- a/kdb-bot/src/bot_api/exception/service_error_code_enum.py +++ b/kdb-bot/src/bot_api/exception/service_error_code_enum.py @@ -1,5 +1,7 @@ from enum import Enum +from werkzeug.exceptions import Unauthorized + class ServiceErrorCode(Enum): @@ -17,3 +19,5 @@ class ServiceErrorCode(Enum): ConnectionFailed = 8 Timeout = 9 MailError = 10 + + Unauthorized = 11 diff --git a/kdb-bot/src/bot_api/route/route.py b/kdb-bot/src/bot_api/route/route.py index 429b24a367..ce8826bcd1 100644 --- a/kdb-bot/src/bot_api/route/route.py +++ b/kdb-bot/src/bot_api/route/route.py @@ -1,12 +1,13 @@ from functools import wraps from typing import Optional -from flask import request +from flask import request, jsonify from flask_cors import cross_origin from bot_api.abc.auth_service_abc import AuthServiceABC from bot_api.exception.service_error_code_enum import ServiceErrorCode from bot_api.exception.service_exception import ServiceException +from bot_api.model.error_dto import ErrorDTO from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC @@ -30,14 +31,20 @@ class Route: bearer = request.headers.get('Authorization') token = bearer.split()[1] - if not token: - raise ServiceException(ServiceErrorCode.InvalidData, f'Token not set') + if token is None: + ex = ServiceException(ServiceErrorCode.Unauthorized, f'Token not set') + error = ErrorDTO(ex.error_code, ex.message) + return jsonify(error.to_dict()), 401 if cls._auth_users is None or cls._auth is None: - raise ServiceException(ServiceErrorCode.InvalidDependencies, f'Authorize is not initialized') + ex = ServiceException(ServiceErrorCode.Unauthorized, f'Authorize is not initialized') + error = ErrorDTO(ex.error_code, ex.message) + return jsonify(error.to_dict()), 401 if not cls._auth.verify_login(token): - raise ServiceException(ServiceErrorCode.InvalidUser, f'Token expired') + ex = ServiceException(ServiceErrorCode.Unauthorized, f'Token expired') + error = ErrorDTO(ex.error_code, ex.message) + return jsonify(error.to_dict()), 401 return await f(*args, **kwargs) diff --git a/kdb-web/src/app/models/error/service-error-code.enum.ts b/kdb-web/src/app/models/error/service-error-code.enum.ts index 5853b5d8fe..5e32aaf18b 100644 --- a/kdb-web/src/app/models/error/service-error-code.enum.ts +++ b/kdb-web/src/app/models/error/service-error-code.enum.ts @@ -12,5 +12,6 @@ export enum ServiceErrorCode { ConnectionFailed = 8, Timeout = 9, - MailError = 10 + MailError = 10, + Unauthorized = 11 } diff --git a/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts b/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts index 598b18d4fe..c972e7f215 100644 --- a/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts +++ b/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts @@ -136,7 +136,7 @@ export class AuthUserComponent implements OnInit { loadNextPage() { this.authService.getFilteredUsers(this.searchCriterions).pipe(catchError(err => { this.loading = false; - return throwError(err); + return throwError(() => err); })).subscribe(list => { this.totalRecords = list.totalCount; this.users = list.users; diff --git a/kdb-web/src/app/services/auth/auth.service.ts b/kdb-web/src/app/services/auth/auth.service.ts index f388e291f1..1608c3f485 100644 --- a/kdb-web/src/app/services/auth/auth.service.ts +++ b/kdb-web/src/app/services/auth/auth.service.ts @@ -2,7 +2,7 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { JwtHelperService } from '@auth0/angular-jwt'; -import { Observable, Subscription } from 'rxjs'; +import { firstValueFrom, Observable, Subscription } from 'rxjs'; import { catchError } from 'rxjs/operators'; import { AdminUpdateUserDTO } from 'src/app/models/auth/admin-update-user.dto'; import { AuthRoles } from 'src/app/models/auth/auth-roles.enum'; @@ -91,6 +91,14 @@ export class AuthService { }); } + verifyLogin(): Observable { + return this.http.get(`${this.appsettings.getApiURL()}/api/auth/verify-login`, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } + forgotPassword(email: string): Observable { const emailJson = JSON.stringify(email); return this.http.post(`${this.appsettings.getApiURL()}/api/auth/forgot-password`, emailJson, { @@ -141,27 +149,6 @@ export class AuthService { }); } - logout(): Subscription | null { - const token = this.getToken(); - this.isLoggedIn = false; - localStorage.removeItem('jwt'); - localStorage.removeItem('rjwt'); - this.router.navigate(['/auth/login']); - - if (token && token.token && token.refreshToken) { - return this.http.post(`${this.appsettings.getApiURL()}/api/auth/revoke`, token, { - headers: new HttpHeaders({ - 'Content-Type': 'application/json' - }) - }).pipe(catchError((error: any) => { - error.error = null; - throw error; - })).subscribe(); - } - - return null - } - deleteUserByMail(mail: string) { return this.http.post(`${this.appsettings.getApiURL()}/api/auth/delete-user-by-mail/${mail}`, { headers: new HttpHeaders({ @@ -190,39 +177,55 @@ export class AuthService { return this.jwtHelper.decodeToken(this.getToken().token); } - async isUserLoggedInAsync(): Promise { - this.isLoggedIn = await this._isUserLoggedInAsync(); - return this.isLoggedIn; + logout(): Subscription | null { + const token = this.getToken(); + + if (token && token.token && token.refreshToken) { + return this.http.post(`${this.appsettings.getApiURL()}/api/auth/revoke`, token, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }).pipe(catchError((error: any) => { + error.error = null; + throw error; + })).subscribe(() => { + this.isLoggedIn = false; + localStorage.removeItem('jwt'); + localStorage.removeItem('rjwt'); + this.router.navigate(['/auth/login']); + }); + } + + return null } - private async _isUserLoggedInAsync(): Promise { + async isUserLoggedInAsync(): Promise { const token = this.getToken(); + if (!token || !token.refreshToken) { this.isLoggedIn = false; return false; } - if (token.token && !this.jwtHelper.isTokenExpired(token.token)) { + const verifiedLogin = await firstValueFrom(await this.verifyLogin()); + + if (verifiedLogin) { this.isLoggedIn = true; return true; } - if (this.isLoggedIn !== false) { + if (this.isLoggedIn) { this.spinnerService.showSpinner(); - const resfreshedToken = await this.refresh(token) - .pipe(catchError((err: Error) => { - this.logout(); - this.spinnerService.hideSpinner(); - throw err; - })) - .toPromise(); + + const resfreshedToken = await firstValueFrom(await this.refresh(token)); + this.spinnerService.hideSpinner(); if (resfreshedToken) { this.saveToken(resfreshedToken); return true; } } - this.isLoggedIn = false; + return false; } diff --git a/kdb-web/src/app/services/error-handler/error-handler.service.ts b/kdb-web/src/app/services/error-handler/error-handler.service.ts index ac8bb59afb..b2ed4f6d02 100644 --- a/kdb-web/src/app/services/error-handler/error-handler.service.ts +++ b/kdb-web/src/app/services/error-handler/error-handler.service.ts @@ -2,6 +2,8 @@ import { HttpErrorResponse } from '@angular/common/http'; import { ErrorHandler, Injectable, Injector } from '@angular/core'; import { Observable, throwError } from 'rxjs'; import { ErrorDTO } from 'src/app/models/error/error-dto'; +import { ServiceErrorCode } from 'src/app/models/error/service-error-code.enum'; +import { AuthService } from '../auth/auth.service'; import { ToastService } from '../toast/toast.service'; @Injectable() @@ -17,6 +19,11 @@ export class ErrorHandlerService implements ErrorHandler { let header = 'Fehler'; const errorDto: ErrorDTO = error.error; + if (errorDto.errorCode === ServiceErrorCode.Unauthorized) { + this.injector.get(AuthService).logout(); + return throwError(() => error); + } + if (errorDto.errorCode !== undefined) { header = 'Fehlercode: ' + errorDto.errorCode; } @@ -29,6 +36,10 @@ export class ErrorHandlerService implements ErrorHandler { this.injector.get(ToastService).error(header, message); } - return throwError(error); + + if (error.status === 401) { + this.injector.get(AuthService).logout(); + } + return throwError(() => error); } } diff --git a/kdb-web/src/app/services/settings/settings.service.ts b/kdb-web/src/app/services/settings/settings.service.ts index 17c292d1bd..ec2b93d737 100644 --- a/kdb-web/src/app/services/settings/settings.service.ts +++ b/kdb-web/src/app/services/settings/settings.service.ts @@ -22,7 +22,7 @@ export class SettingsService { this.http.get('../../assets/config.json') .pipe(catchError(error => { reject(error); - return throwError(error); + return throwError(() => error); })).subscribe(settings => { this.appsettings = settings; resolve(settings); diff --git a/kdb-web/src/app/services/theme/theme.service.ts b/kdb-web/src/app/services/theme/theme.service.ts index 47537679db..f83a4510d1 100644 --- a/kdb-web/src/app/services/theme/theme.service.ts +++ b/kdb-web/src/app/services/theme/theme.service.ts @@ -1,4 +1,5 @@ import { Injectable } from '@angular/core'; +import { Subject } from 'rxjs'; import { Themes } from 'src/app/models/view/themes.enum'; import { AuthService } from '../auth/auth.service'; @@ -13,9 +14,14 @@ export class ThemeService { isSidebarOpen = false; hasLangChanged = false; + isSidebarOpen$ = new Subject(); + constructor( private authService: AuthService ) { + this.isSidebarOpen$.subscribe(isSidebarOpen => { + this.isSidebarOpen = isSidebarOpen + }); this.loadTheme(); this.loadMenu(); this.themeName = null; @@ -93,6 +99,6 @@ export class ThemeService { setSideWidth($event: any): void { this.sidebarWidth = $event ? '150px' : '50px'; - this.isSidebarOpen = $event; + this.isSidebarOpen$.next($event) } } From 1a3126dfc5b181658489fb35476c1aea52bfd7ec Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sun, 16 Oct 2022 12:57:27 +0200 Subject: [PATCH 026/102] Removed themeService from templates #70 --- kdb-web/src/app/app.component.html | 8 +-- kdb-web/src/app/app.component.ts | 19 +++++- .../app/components/header/header.component.ts | 5 +- .../components/sidebar/sidebar.component.ts | 63 ++++++++++--------- .../modules/shared/guards/auth/auth.guard.ts | 11 ++-- kdb-web/src/app/services/auth/auth.service.ts | 14 +++-- .../src/app/services/theme/theme.service.ts | 27 +++++--- 7 files changed, 91 insertions(+), 56 deletions(-) diff --git a/kdb-web/src/app/app.component.html b/kdb-web/src/app/app.component.html index a9daaf7237..94cdd058a1 100644 --- a/kdb-web/src/app/app.component.html +++ b/kdb-web/src/app/app.component.html @@ -1,11 +1,11 @@ -
+
- +
-
diff --git a/kdb-web/src/app/app.component.ts b/kdb-web/src/app/app.component.ts index 6d8046ff17..4bf3415267 100644 --- a/kdb-web/src/app/app.component.ts +++ b/kdb-web/src/app/app.component.ts @@ -10,15 +10,32 @@ import { ThemeService } from './services/theme/theme.service'; }) export class AppComponent implements OnInit { + themeName!: string; + sidebarWidth!: string; + + isLoggedIn: boolean = false; + constructor( public authService: AuthService, - public themeService: ThemeService, + private themeService: ThemeService, private socket: SocketService ) { } ngOnInit(): void { + this.themeService.sidebarWidth$.subscribe(value => { + this.sidebarWidth = value; + }); + this.themeService.themeName$.subscribe(value => { + this.themeName = value; + }); + this.socket.startSocket(); this.themeService.loadTheme(); this.themeService.loadMenu(); } + + + setSideWidth($event: any): void { + this.themeService.setSideWidth($event); + } } diff --git a/kdb-web/src/app/components/header/header.component.ts b/kdb-web/src/app/components/header/header.component.ts index 6d4ad0eeeb..ff71d92fca 100644 --- a/kdb-web/src/app/components/header/header.component.ts +++ b/kdb-web/src/app/components/header/header.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, OnInit, Output } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { Router } from '@angular/router'; import { LangChangeEvent, TranslateService } from '@ngx-translate/core'; import { MenuItem, PrimeNGConfig } from 'primeng/api'; @@ -14,8 +14,6 @@ import { ThemeService } from 'src/app/services/theme/theme.service'; styleUrls: ['./header.component.scss'] }) export class HeaderComponent implements OnInit { - @Output() isSidebarFullWidth: EventEmitter = new EventEmitter(this.themeService.isSidebarOpen); - langList: MenuItem[] = []; themeList: MenuItem[] = []; userMenuList!: MenuItem[]; @@ -112,7 +110,6 @@ export class HeaderComponent implements OnInit { toggleMenu(): void { this.themeService.setIsMenuOpen(!this.themeService.isSidebarOpen); - this.isSidebarFullWidth.emit(this.themeService.isSidebarOpen); } changeTheme(name: string): void { diff --git a/kdb-web/src/app/components/sidebar/sidebar.component.ts b/kdb-web/src/app/components/sidebar/sidebar.component.ts index a87eb35f74..ddc840eac4 100644 --- a/kdb-web/src/app/components/sidebar/sidebar.component.ts +++ b/kdb-web/src/app/components/sidebar/sidebar.component.ts @@ -3,50 +3,57 @@ import { LangChangeEvent, TranslateService } from '@ngx-translate/core'; import { MenuItem } from 'primeng/api'; import { AuthRoles } from 'src/app/models/auth/auth-roles.enum'; import { AuthService } from 'src/app/services/auth/auth.service'; +import { ThemeService } from 'src/app/services/theme/theme.service'; @Component({ selector: 'app-sidebar', templateUrl: './sidebar.component.html', styleUrls: ['./sidebar.component.scss'] }) -export class SidebarComponent implements OnInit, OnChanges { +export class SidebarComponent implements OnInit { - @Input() isSidebarOpen!: boolean; + isSidebarOpen: boolean = true; menuItems!: MenuItem[]; constructor( private authService: AuthService, - private translateService: TranslateService + private translateService: TranslateService, + private themeService: ThemeService ) { } ngOnInit(): void { - this.translateService.onLangChange.subscribe(async (event: LangChangeEvent) => { - await this.setMenu(this.isSidebarOpen); + this.themeService.isSidebarOpen$.subscribe(value => { + this.isSidebarOpen = value; + this.setMenu(); + }); + + + this.translateService.onLangChange.subscribe((event: LangChangeEvent) => { + this.setMenu(); + }); + this.setMenu(); + } + + setMenu() { + + this.authService.hasUserPermission(AuthRoles.Admin).then(hasPermission => { + this.menuItems = []; + this.menuItems = [ + { label: this.isSidebarOpen ? this.translateService.instant('sidebar.dashboard') : '', icon: 'pi pi-th-large', routerLink: 'dashboard' }, + ]; + + if (!hasPermission) { + return; + } + + this.menuItems.push( + { separator: true }, + { label: this.isSidebarOpen ? this.translateService.instant('sidebar.config') : '', icon: 'pi pi-cog', routerLink: '/admin/settings' }, + { label: this.isSidebarOpen ? this.translateService.instant('sidebar.auth_user_list') : '', icon: 'pi pi-user-edit', routerLink: '/admin/users' }, + ); + this.menuItems = this.menuItems.slice(); }); } - async setMenu(isSidebarOpen: boolean) { - this.menuItems = []; - this.menuItems = [ - { label: isSidebarOpen ? this.translateService.instant('sidebar.dashboard') : '', icon: 'pi pi-th-large', routerLink: 'dashboard' }, - ]; - - if (await this.authService.hasUserPermission(AuthRoles.Admin)) { - this.menuItems.push( - { separator: true }, - { label: isSidebarOpen ? this.translateService.instant('sidebar.config') : '', icon: 'pi pi-cog', routerLink: '/admin/settings' }, - { label: isSidebarOpen ? this.translateService.instant('sidebar.auth_user_list') : '', icon: 'pi pi-user-edit', routerLink: '/admin/users' }, - ); - this.menuItems = this.menuItems.slice(); - } - } - - async ngOnChanges(changes: SimpleChanges): Promise { - if (!changes) - return; - - await this.setMenu(changes['isSidebarOpen'].currentValue); - } - } diff --git a/kdb-web/src/app/modules/shared/guards/auth/auth.guard.ts b/kdb-web/src/app/modules/shared/guards/auth/auth.guard.ts index 694dc644a1..deb1be4028 100644 --- a/kdb-web/src/app/modules/shared/guards/auth/auth.guard.ts +++ b/kdb-web/src/app/modules/shared/guards/auth/auth.guard.ts @@ -28,10 +28,13 @@ export class AuthGuard implements CanActivate { const role = route.data['role']; if (role) { - if (!await this.authService.hasUserPermission(role)) { - this.router.navigate(['/dashboard']); - return false; - } + this.authService.hasUserPermission(role).then(hasPermission => { + if (!hasPermission) { + this.router.navigate(['/dashboard']); + return false; + } + return true; + }); } return true; } diff --git a/kdb-web/src/app/services/auth/auth.service.ts b/kdb-web/src/app/services/auth/auth.service.ts index 1608c3f485..5c007891a7 100644 --- a/kdb-web/src/app/services/auth/auth.service.ts +++ b/kdb-web/src/app/services/auth/auth.service.ts @@ -229,12 +229,14 @@ export class AuthService { return false; } - async hasUserPermission(role: AuthRoles): Promise { - if (!role || !await this.isUserLoggedInAsync()) { - return false; - } - const token = this.getDecodedToken(); - return AuthRoles[token['role']] === AuthRoles[role]; + hasUserPermission(role: AuthRoles): Promise { + return this.isUserLoggedInAsync().then(isLoggedIn => { + if (!role || !isLoggedIn) { + return false; + } + const token = this.getDecodedToken(); + return AuthRoles[token['role']] === AuthRoles[role]; + }); } getEMailFromDecodedToken(token: { [key: string]: any }): string | null { diff --git a/kdb-web/src/app/services/theme/theme.service.ts b/kdb-web/src/app/services/theme/theme.service.ts index f83a4510d1..0d3dae59fb 100644 --- a/kdb-web/src/app/services/theme/theme.service.ts +++ b/kdb-web/src/app/services/theme/theme.service.ts @@ -1,4 +1,5 @@ import { Injectable } from '@angular/core'; +import { LangChangeEvent, TranslateService } from '@ngx-translate/core'; import { Subject } from 'rxjs'; import { Themes } from 'src/app/models/view/themes.enum'; import { AuthService } from '../auth/auth.service'; @@ -8,23 +9,31 @@ import { AuthService } from '../auth/auth.service'; }) export class ThemeService { - themeName: string | null; + themeName: string = Themes.Default; sidebarWidth = '150px'; isSidebarOpen = false; hasLangChanged = false; + themeName$ = new Subject(); isSidebarOpen$ = new Subject(); + sidebarWidth$ = new Subject(); constructor( private authService: AuthService ) { - this.isSidebarOpen$.subscribe(isSidebarOpen => { - this.isSidebarOpen = isSidebarOpen + this.themeName$.subscribe(themeName => { + this.themeName = themeName; }); + this.isSidebarOpen$.subscribe(isSidebarOpen => { + this.isSidebarOpen = isSidebarOpen; + }); + this.sidebarWidth$.subscribe(sidebarWidth => { + this.sidebarWidth = sidebarWidth; + }); + this.loadTheme(); this.loadMenu(); - this.themeName = null; } loadTheme(): void { @@ -53,7 +62,7 @@ export class ThemeService { this.authService.isUserLoggedInAsync().then(result => { if (!result) { localStorage.setItem(`default_themeName`, Themes.Default); - this.themeName = Themes.Default; + this.themeName$.next(Themes.Default); } const token = this.authService.getDecodedToken(); @@ -62,7 +71,7 @@ export class ThemeService { localStorage.setItem(`${mail}_themeName`, name); } localStorage.setItem(`default_themeName`, name); - this.themeName = name; + this.themeName$.next(name); }); } @@ -97,8 +106,8 @@ export class ThemeService { this.setSideWidth(isMenuOpen); } - setSideWidth($event: any): void { - this.sidebarWidth = $event ? '150px' : '50px'; - this.isSidebarOpen$.next($event) + setSideWidth(isSidebarOpen: boolean): void { + this.sidebarWidth$.next(isSidebarOpen ? '150px' : '50px'); + this.isSidebarOpen$.next(isSidebarOpen); } } From dbbd2b54c46172b9ff655b954c425a18e5ea119e Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sun, 16 Oct 2022 13:09:26 +0200 Subject: [PATCH 027/102] Fixed load menu #70 --- kdb-web/src/app/app.component.ts | 1 - .../app/components/sidebar/sidebar.component.ts | 15 +++++++-------- kdb-web/src/app/services/theme/theme.service.ts | 7 +++---- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/kdb-web/src/app/app.component.ts b/kdb-web/src/app/app.component.ts index 4bf3415267..22a6a7cd34 100644 --- a/kdb-web/src/app/app.component.ts +++ b/kdb-web/src/app/app.component.ts @@ -31,7 +31,6 @@ export class AppComponent implements OnInit { this.socket.startSocket(); this.themeService.loadTheme(); - this.themeService.loadMenu(); } diff --git a/kdb-web/src/app/components/sidebar/sidebar.component.ts b/kdb-web/src/app/components/sidebar/sidebar.component.ts index ddc840eac4..cbf13c6f7c 100644 --- a/kdb-web/src/app/components/sidebar/sidebar.component.ts +++ b/kdb-web/src/app/components/sidebar/sidebar.component.ts @@ -20,33 +20,32 @@ export class SidebarComponent implements OnInit { private authService: AuthService, private translateService: TranslateService, private themeService: ThemeService - ) { } - - ngOnInit(): void { + ) { this.themeService.isSidebarOpen$.subscribe(value => { this.isSidebarOpen = value; this.setMenu(); }); - this.translateService.onLangChange.subscribe((event: LangChangeEvent) => { this.setMenu(); }); - this.setMenu(); + } + + ngOnInit(): void { + this.themeService.loadMenu(); } setMenu() { - this.authService.hasUserPermission(AuthRoles.Admin).then(hasPermission => { this.menuItems = []; this.menuItems = [ { label: this.isSidebarOpen ? this.translateService.instant('sidebar.dashboard') : '', icon: 'pi pi-th-large', routerLink: 'dashboard' }, ]; - + if (!hasPermission) { return; } - + this.menuItems.push( { separator: true }, { label: this.isSidebarOpen ? this.translateService.instant('sidebar.config') : '', icon: 'pi pi-cog', routerLink: '/admin/settings' }, diff --git a/kdb-web/src/app/services/theme/theme.service.ts b/kdb-web/src/app/services/theme/theme.service.ts index 0d3dae59fb..914ba774ef 100644 --- a/kdb-web/src/app/services/theme/theme.service.ts +++ b/kdb-web/src/app/services/theme/theme.service.ts @@ -27,13 +27,13 @@ export class ThemeService { }); this.isSidebarOpen$.subscribe(isSidebarOpen => { this.isSidebarOpen = isSidebarOpen; + this.sidebarWidth$.next(isSidebarOpen ? '150px' : '50px'); }); this.sidebarWidth$.subscribe(sidebarWidth => { this.sidebarWidth = sidebarWidth; }); - + this.loadTheme(); - this.loadMenu(); } loadTheme(): void { @@ -87,7 +87,7 @@ export class ThemeService { let isMenuOpen = true; let isMenuOpenStr = localStorage.getItem(`${mail}_isMenuOpen`); if (isMenuOpenStr) { - isMenuOpen = Boolean(isMenuOpenStr); + isMenuOpen = JSON.parse(isMenuOpenStr); } this.setIsMenuOpen(isMenuOpen); @@ -107,7 +107,6 @@ export class ThemeService { } setSideWidth(isSidebarOpen: boolean): void { - this.sidebarWidth$.next(isSidebarOpen ? '150px' : '50px'); this.isSidebarOpen$.next(isSidebarOpen); } } From d5ad5ded883d63f3a0f5be3bd520975b8d571d94 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sun, 16 Oct 2022 14:49:46 +0200 Subject: [PATCH 028/102] Fixed header styling #70 --- kdb-web/src/styles.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kdb-web/src/styles.scss b/kdb-web/src/styles.scss index 8964e79cb7..ee146861c3 100644 --- a/kdb-web/src/styles.scss +++ b/kdb-web/src/styles.scss @@ -38,7 +38,6 @@ header { display: flex; align-items: center; justify-content: center; - margin: 0px 5px; .p-button.p-button-text { border: none; @@ -55,6 +54,7 @@ header { text-align: right; flex: 1; justify-content: flex-end; + margin: 0px 5px 0px 0px; } .p-menu-overlay { From f319e89473bac2605445ea2eed3a578a2df92654 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sun, 16 Oct 2022 16:01:37 +0200 Subject: [PATCH 029/102] Fixed login state problems #70 --- kdb-web/src/app/app.component.html | 2 +- kdb-web/src/app/app.component.ts | 7 ++- kdb-web/src/app/services/auth/auth.service.ts | 48 +++++++++++-------- .../src/app/services/socket/socket.service.ts | 2 +- 4 files changed, 36 insertions(+), 23 deletions(-) diff --git a/kdb-web/src/app/app.component.html b/kdb-web/src/app/app.component.html index 94cdd058a1..a2dc5b5036 100644 --- a/kdb-web/src/app/app.component.html +++ b/kdb-web/src/app/app.component.html @@ -1,5 +1,5 @@
- +
diff --git a/kdb-web/src/app/app.component.ts b/kdb-web/src/app/app.component.ts index 22a6a7cd34..72139e6689 100644 --- a/kdb-web/src/app/app.component.ts +++ b/kdb-web/src/app/app.component.ts @@ -16,7 +16,7 @@ export class AppComponent implements OnInit { isLoggedIn: boolean = false; constructor( - public authService: AuthService, + private authService: AuthService, private themeService: ThemeService, private socket: SocketService ) { } @@ -28,9 +28,12 @@ export class AppComponent implements OnInit { this.themeService.themeName$.subscribe(value => { this.themeName = value; }); + this.authService.isLoggedIn$.subscribe(value => { + this.isLoggedIn = value; + }); - this.socket.startSocket(); this.themeService.loadTheme(); + this.socket.startSocket(); } diff --git a/kdb-web/src/app/services/auth/auth.service.ts b/kdb-web/src/app/services/auth/auth.service.ts index 5c007891a7..83a9bf22e6 100644 --- a/kdb-web/src/app/services/auth/auth.service.ts +++ b/kdb-web/src/app/services/auth/auth.service.ts @@ -2,7 +2,7 @@ import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { JwtHelperService } from '@auth0/angular-jwt'; -import { firstValueFrom, Observable, Subscription } from 'rxjs'; +import { firstValueFrom, Observable, Subject, Subscription } from 'rxjs'; import { catchError } from 'rxjs/operators'; import { AdminUpdateUserDTO } from 'src/app/models/auth/admin-update-user.dto'; import { AuthRoles } from 'src/app/models/auth/auth-roles.enum'; @@ -21,8 +21,8 @@ import { SpinnerService } from '../spinner/spinner.service'; }) export class AuthService { - invalidLogin!: boolean; - isLoggedIn!: boolean; + private isLoggedIn!: boolean; + isLoggedIn$ = new Subject(); constructor( private appsettings: SettingsService, @@ -31,7 +31,9 @@ export class AuthService { private jwtHelper: JwtHelperService, private spinnerService: SpinnerService ) { - this.isUserLoggedInAsync(); + this.isLoggedIn$.subscribe(value => { + this.isLoggedIn = value; + }); } /* data requests */ @@ -187,14 +189,20 @@ export class AuthService { }) }).pipe(catchError((error: any) => { error.error = null; + this.isLoggedIn$.next(false); + localStorage.removeItem('rjwt'); + this.router.navigate(['/auth/login']); throw error; })).subscribe(() => { - this.isLoggedIn = false; + this.isLoggedIn$.next(false); localStorage.removeItem('jwt'); localStorage.removeItem('rjwt'); this.router.navigate(['/auth/login']); }); } + this.isLoggedIn$.next(false); + localStorage.removeItem('rjwt'); + this.router.navigate(['/auth/login']); return null } @@ -203,15 +211,19 @@ export class AuthService { const token = this.getToken(); if (!token || !token.refreshToken) { - this.isLoggedIn = false; + this.isLoggedIn$.next(false); return false; } - const verifiedLogin = await firstValueFrom(await this.verifyLogin()); - - if (verifiedLogin) { - this.isLoggedIn = true; - return true; + try { + const verifiedLogin = await firstValueFrom(this.verifyLogin()); + if (verifiedLogin) { + this.isLoggedIn$.next(true); + return true; + } + } catch (error: unknown) { + this.isLoggedIn$.next(false); + return false; } if (this.isLoggedIn) { @@ -229,14 +241,12 @@ export class AuthService { return false; } - hasUserPermission(role: AuthRoles): Promise { - return this.isUserLoggedInAsync().then(isLoggedIn => { - if (!role || !isLoggedIn) { - return false; - } - const token = this.getDecodedToken(); - return AuthRoles[token['role']] === AuthRoles[role]; - }); + async hasUserPermission(role: AuthRoles): Promise { + if (!role || !await this.isUserLoggedInAsync()) { + return false; + } + const token = this.getDecodedToken(); + return AuthRoles[token['role']] === AuthRoles[role]; } getEMailFromDecodedToken(token: { [key: string]: any }): string | null { diff --git a/kdb-web/src/app/services/socket/socket.service.ts b/kdb-web/src/app/services/socket/socket.service.ts index 4493587408..a29bba2c65 100644 --- a/kdb-web/src/app/services/socket/socket.service.ts +++ b/kdb-web/src/app/services/socket/socket.service.ts @@ -20,10 +20,10 @@ export class SocketService { private spinnerService: SpinnerService, private messageService: MessageService, ) { - this.socket = io(`${settingsService.getApiURL()}`) } startSocket() { + this.socket = io(`${this.settingsService.getApiURL()}`) this.socket.on('connect', () => { if (this.disconnected) { if (this.spinnerService.showSpinnerState) { From c5f371e0d545acef4275d009bc3dbdd5bbcd1737 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sun, 16 Oct 2022 21:10:20 +0200 Subject: [PATCH 030/102] Fixed update user #70 --- .../components/auth-user/auth-user.component.html | 4 ++-- kdb-web/src/assets/i18n/de.json | 14 +++++++------- kdb-web/src/assets/i18n/en.json | 14 +++++++------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.html b/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.html index 1cb83a5569..9f810bda9f 100644 --- a/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.html +++ b/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.html @@ -43,10 +43,10 @@
- +
{{'admin.auth_users.headers.e_mail' | translate}}
- +
diff --git a/kdb-web/src/assets/i18n/de.json b/kdb-web/src/assets/i18n/de.json index b51660d4e1..894bd46195 100644 --- a/kdb-web/src/assets/i18n/de.json +++ b/kdb-web/src/assets/i18n/de.json @@ -68,21 +68,21 @@ "no_entries_found": "Keine Einträge gefunden", "message": { "invalid_email": "Ungültige E-Mail", - "invalid_email_d": "Die E-Mail {{eMail}} ist nicht gültig!", + "invalid_email_d": "Die E-Mail {{email}} ist nicht gültig!", "user_already_exists": "Benutzer existiert bereits", - "user_already_exists_d": "Der Benutzer {{eMail}} existiert bereits!", + "user_already_exists_d": "Der Benutzer {{email}} existiert bereits!", "user_added": "Benutzer hinzugefügt", - "user_added_d": "Benutzer {{eMail}} erfolgreich hinzugefügt", + "user_added_d": "Benutzer {{email}} erfolgreich hinzugefügt", "user_change_failed": "Benutzer änderung fehlgeschlagen", - "user_change_failed_d": "Benutzer {{eMail}} konnte nicht geändert werden!", + "user_change_failed_d": "Benutzer {{email}} konnte nicht geändert werden!", "user_changed": "Benutzer geändert", - "user_changed_d": "Benutzer {{eMail}} erfolgreich geändert", + "user_changed_d": "Benutzer {{email}} erfolgreich geändert", "cannot_delete_user": "Benutzer kann nicht gelöscht werden", "logon_with_another_user": "Loggen Sie sich mit einem anderen Benutzer ein, um diesen Benutzer zu löschen!", "user_delete": "Benutzer löschen", - "user_delete_q": "Sind Sie sich sicher, dass Sie {{eMail}} löschen möchten?", + "user_delete_q": "Sind Sie sich sicher, dass Sie {{email}} löschen möchten?", "user_deleted": "Benutzer gelöscht", - "user_deleted_d": "Benutzer {{eMail}} erfolgreich gelöscht" + "user_deleted_d": "Benutzer {{email}} erfolgreich gelöscht" } } }, diff --git a/kdb-web/src/assets/i18n/en.json b/kdb-web/src/assets/i18n/en.json index 28a8c47b12..d289c560e2 100644 --- a/kdb-web/src/assets/i18n/en.json +++ b/kdb-web/src/assets/i18n/en.json @@ -67,21 +67,21 @@ "no_entries_found": "No entries found", "message": { "invalid_email": "Invalid E-Mail", - "invalid_email_d": "The e-mail {{eMail}} is not valid!", + "invalid_email_d": "The e-mail {{email}} is not valid!", "user_already_exists": "User already exists", - "user_already_exists_d": "The user {{eMail}} already exists!", + "user_already_exists_d": "The user {{email}} already exists!", "user_added": "User added", - "user_added_d": "User {{eMail}} successfully added", + "user_added_d": "User {{email}} successfully added", "user_change_failed": "User change failed", - "user_change_failed_d": "User {{eMail}} could not be changed!", + "user_change_failed_d": "User {{email}} could not be changed!", "user_changed": "User changed", - "user_changed_d": "User {{eMail}} changed successfully", + "user_changed_d": "User {{email}} changed successfully", "cannot_delete_user": "User cannot be deleted", "logon_with_another_user": "Log in with another user to delete this user!", "user_delete": "Delete user", - "user_delete_q": "Are you sure you want to delete {{eMail}}?", + "user_delete_q": "Are you sure you want to delete {{email}}?", "user_deleted": "User deleted", - "user_deleted_d": "User {{eMail}} successfully deleted" + "user_deleted_d": "User {{email}} successfully deleted" } } }, From 29fa35dffe1d2383a5b6c8af2e5b7b808bf5da4a Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sun, 16 Oct 2022 21:16:04 +0200 Subject: [PATCH 031/102] Fixed update user #70 --- kdb-bot/src/bot_api/controller/auth_controller.py | 2 +- kdb-bot/src/bot_api/service/auth_service.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/kdb-bot/src/bot_api/controller/auth_controller.py b/kdb-bot/src/bot_api/controller/auth_controller.py index 5342df92c6..a23d490dff 100644 --- a/kdb-bot/src/bot_api/controller/auth_controller.py +++ b/kdb-bot/src/bot_api/controller/auth_controller.py @@ -112,7 +112,7 @@ class AuthController: @Route.authorize async def update_user_as_admin(self): dto: UpdateAuthUserDTO = JSONProcessor.process(UpdateAuthUserDTO, request.get_json(force=True, silent=True)) - await self._auth_service.update_user_async(dto) + await self._auth_service.update_user_as_admin_async(dto) return '', 200 @Route.post(f'{BasePath}/refresh') diff --git a/kdb-bot/src/bot_api/service/auth_service.py b/kdb-bot/src/bot_api/service/auth_service.py index 0a78a9c448..e1e4a2b943 100644 --- a/kdb-bot/src/bot_api/service/auth_service.py +++ b/kdb-bot/src/bot_api/service/auth_service.py @@ -273,6 +273,7 @@ class AuthService(AuthServiceABC): if user.auth_role == update_user_dto.auth_user.auth_role and user.auth_role != update_user_dto.new_auth_user.auth_role: user.auth_role = update_user_dto.new_auth_user.auth_role + self._auth_users.update_auth_user(user) self._db.save_changes() async def delete_auth_user_by_email_async(self, email: str): From f634ad552e3aa1fe56a35f3e06c6e30018b57965 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sun, 16 Oct 2022 21:29:58 +0200 Subject: [PATCH 032/102] Fixed settings dto #70 --- .../src/bot_api/controller/gui_controller.py | 21 +++++++++++-------- kdb-bot/src/bot_api/model/settings_dto.py | 2 +- kdb-bot/src/bot_api/model/version_dto.py | 16 ++++++++++++++ 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/kdb-bot/src/bot_api/controller/gui_controller.py b/kdb-bot/src/bot_api/controller/gui_controller.py index dccc2099b6..d956e90099 100644 --- a/kdb-bot/src/bot_api/controller/gui_controller.py +++ b/kdb-bot/src/bot_api/controller/gui_controller.py @@ -4,8 +4,10 @@ from cpl_core.configuration import ConfigurationABC from cpl_core.environment import ApplicationEnvironmentABC from cpl_core.mailing import EMail, EMailClientABC, EMailClientSettings from cpl_translation import TranslatePipe +from flask import jsonify from bot_api.api import Api +from bot_api.configuration.authentication_settings import AuthenticationSettings from bot_api.logging.api_logger import ApiLogger from bot_api.model.settings_dto import SettingsDTO from bot_api.model.version_dto import VersionDTO @@ -23,7 +25,8 @@ class GuiController: t: TranslatePipe, api: Api, mail_settings: EMailClientSettings, - mailer: EMailClientABC + mailer: EMailClientABC, + auth_settings: AuthenticationSettings ): self._config = config self._env = env @@ -32,6 +35,7 @@ class GuiController: self._api = api self._mail_settings = mail_settings self._mailer = mailer + self._auth_settings = auth_settings @Route.get(f'{BasePath}/api-version') async def api_version(self): @@ -42,29 +46,27 @@ class GuiController: @Route.get(f'{BasePath}/settings') @Route.authorize async def settings(self): - # TODO: Authentication import bot_api version = bot_api.version_info - return SettingsDTO( + return jsonify(SettingsDTO( '', VersionDTO(version.major, version.minor, version.micro), os.path.abspath(os.path.join(self._env.working_directory, 'config')), - '', '/', - 0, - 0, + '/', + self._auth_settings.token_expire_time, + self._auth_settings.refresh_token_expire_time, self._mail_settings.user_name, self._mail_settings.port, self._mail_settings.host, self._mail_settings.user_name, self._mail_settings.user_name, - ).to_dict() + ).to_dict()) - @Route.get(f'{BasePath}/send-test-mail/') + @Route.post(f'{BasePath}/send-test-mail/') @Route.authorize async def send_test_mail(self, email: str): - # TODO: Authentication mail = EMail() mail.add_header('Mime-Version: 1.0') mail.add_header('Content-Type: text/plain; charset=utf-8') @@ -73,3 +75,4 @@ class GuiController: mail.subject = self._t.transform('api.api.test_mail.subject') mail.body = self._t.transform('api.api.test_mail.message').format(self._env.host_name, self._env.environment_name) self._mailer.send_mail(mail) + return '', 200 diff --git a/kdb-bot/src/bot_api/model/settings_dto.py b/kdb-bot/src/bot_api/model/settings_dto.py index 567f393126..09df375cf4 100644 --- a/kdb-bot/src/bot_api/model/settings_dto.py +++ b/kdb-bot/src/bot_api/model/settings_dto.py @@ -53,7 +53,7 @@ class SettingsDTO(DtoABC): def to_dict(self) -> dict: return { 'webVersion': self._web_version, - 'apiVersion': self._api_version.to_dict(), + 'apiVersion': self._api_version.str, 'configPath': self._config_path, 'webBaseURL': self._web_base_url, 'apiBaseURL': self._api_base_url, diff --git a/kdb-bot/src/bot_api/model/version_dto.py b/kdb-bot/src/bot_api/model/version_dto.py index c1504478e9..c15413a0ee 100644 --- a/kdb-bot/src/bot_api/model/version_dto.py +++ b/kdb-bot/src/bot_api/model/version_dto.py @@ -14,6 +14,22 @@ class VersionDTO(DtoABC): self._minor = minor self._micro = micro + @property + def major(self) -> str: + return self._major + + @property + def minor(self) -> str: + return self._minor + + @property + def micro(self) -> str: + return self._micro + + @property + def str(self) -> str: + return f'{self._major}.{self._minor}.{self._micro}' + def from_dict(self, values: dict): self._major = values['major'] self._minor = values['minor'] From 90bfee23b4ac876bb9dd8cb41f59a465737ac96e Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sun, 16 Oct 2022 21:36:08 +0200 Subject: [PATCH 033/102] Added logic to load api after bot #70 --- kdb-bot/src/bot/application.py | 5 ++--- kdb-bot/src/bot/module_list.py | 2 +- ...h_user_transformer_abc.py => transformer_abc.py} | 2 +- kdb-bot/src/bot_api/api_module.py | 5 +++++ kdb-bot/src/bot_api/event/bot_api_on_ready_event.py | 13 +++++++++++++ .../bot_api/transformer/auth_user_transformer.py | 4 ++-- 6 files changed, 24 insertions(+), 7 deletions(-) rename kdb-bot/src/bot_api/abc/{auth_user_transformer_abc.py => transformer_abc.py} (90%) create mode 100644 kdb-bot/src/bot_api/event/bot_api_on_ready_event.py diff --git a/kdb-bot/src/bot/application.py b/kdb-bot/src/bot/application.py index 6c65a6b49c..1cfa2caa12 100644 --- a/kdb-bot/src/bot/application.py +++ b/kdb-bot/src/bot/application.py @@ -43,10 +43,9 @@ class Application(DiscordBotApplicationABC): async def main(self): try: self._logger.debug(__name__, f'Starting...') - if self._feature_flags.get_flag(FeatureFlagsEnum.api_module): - self._api.start() - if self._feature_flags.get_flag(FeatureFlagsEnum.api_only) and self._environment.environment_name == 'development': + if self._feature_flags.get_flag(FeatureFlagsEnum.api_module) and self._feature_flags.get_flag(FeatureFlagsEnum.api_only) and self._environment.environment_name == 'development': + self._api.start() self._api.join() return diff --git a/kdb-bot/src/bot/module_list.py b/kdb-bot/src/bot/module_list.py index 866b7d677f..b818ad4bcd 100644 --- a/kdb-bot/src/bot/module_list.py +++ b/kdb-bot/src/bot/module_list.py @@ -21,13 +21,13 @@ class ModuleList: return List(type, [ CoreModule, # has to be first! DataModule, - ApiModule, AdminModule, AutoRoleModule, BaseModule, DatabaseModule, ModeratorModule, PermissionModule, + ApiModule, # has to be last! BootLogModule, CoreExtensionModule, diff --git a/kdb-bot/src/bot_api/abc/auth_user_transformer_abc.py b/kdb-bot/src/bot_api/abc/transformer_abc.py similarity index 90% rename from kdb-bot/src/bot_api/abc/auth_user_transformer_abc.py rename to kdb-bot/src/bot_api/abc/transformer_abc.py index fd273847c5..6ff2f67676 100644 --- a/kdb-bot/src/bot_api/abc/auth_user_transformer_abc.py +++ b/kdb-bot/src/bot_api/abc/transformer_abc.py @@ -5,7 +5,7 @@ from cpl_core.database import TableABC from bot_api.abc.dto_abc import DtoABC -class AuthUserTransformerABC: +class TransformerABC: @staticmethod @abstractmethod diff --git a/kdb-bot/src/bot_api/api_module.py b/kdb-bot/src/bot_api/api_module.py index 6474a3e522..d6d659ecba 100644 --- a/kdb-bot/src/bot_api/api_module.py +++ b/kdb-bot/src/bot_api/api_module.py @@ -4,6 +4,7 @@ from cpl_core.configuration import ConfigurationABC from cpl_core.dependency_injection import ServiceCollectionABC from cpl_core.environment import ApplicationEnvironmentABC from cpl_core.mailing import EMailClientABC, EMailClient +from cpl_discord.discord_event_types_enum import DiscordEventTypesEnum from cpl_discord.service.discord_collection_abc import DiscordCollectionABC from flask import Flask @@ -12,6 +13,7 @@ from bot_api.api import Api from bot_api.api_thread import ApiThread from bot_api.controller.gui_controller import GuiController from bot_api.controller.auth_controller import AuthController +from bot_api.event.bot_api_on_ready_event import BotApiOnReadyEvent from bot_api.service.auth_service import AuthService from bot_core.abc.module_abc import ModuleABC from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum @@ -39,3 +41,6 @@ class ApiModule(ModuleABC): services.add_transient(AuthServiceABC, AuthService) services.add_transient(AuthController) services.add_transient(GuiController) + + # cpl-discord + self._dc.add_event(DiscordEventTypesEnum.on_ready.value, BotApiOnReadyEvent) diff --git a/kdb-bot/src/bot_api/event/bot_api_on_ready_event.py b/kdb-bot/src/bot_api/event/bot_api_on_ready_event.py new file mode 100644 index 0000000000..ca63a03c77 --- /dev/null +++ b/kdb-bot/src/bot_api/event/bot_api_on_ready_event.py @@ -0,0 +1,13 @@ +from cpl_discord.events import OnReadyABC + +from bot_api.api_thread import ApiThread + + +class BotApiOnReadyEvent(OnReadyABC): + + def __init__(self, api: ApiThread): + OnReadyABC.__init__(self) + self._api = api + + async def on_ready(self): + self._api.start() diff --git a/kdb-bot/src/bot_api/transformer/auth_user_transformer.py b/kdb-bot/src/bot_api/transformer/auth_user_transformer.py index b324445b6b..3f84a9399a 100644 --- a/kdb-bot/src/bot_api/transformer/auth_user_transformer.py +++ b/kdb-bot/src/bot_api/transformer/auth_user_transformer.py @@ -1,12 +1,12 @@ from datetime import datetime, timezone -from bot_api.abc.auth_user_transformer_abc import AuthUserTransformerABC +from bot_api.abc.transformer_abc import TransformerABC from bot_api.model.auth_user_dto import AuthUserDTO from bot_data.model.auth_role_enum import AuthRoleEnum from bot_data.model.auth_user import AuthUser -class AuthUserTransformer(AuthUserTransformerABC): +class AuthUserTransformer(TransformerABC): @staticmethod def to_db(dto: AuthUser) -> AuthUser: From 1857473ccc1cb2ff706df625a0ca2636032dcd69 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sun, 16 Oct 2022 20:59:02 +0200 Subject: [PATCH 034/102] Added logic to get discord servers #72 --- kdb-bot/src/bot/config/feature-flags.json | 3 +- .../bot_api/controller/discord/__init__.py | 0 .../controller/discord/server_controller.py | 39 +++++++++++++++ kdb-bot/src/bot_api/event/__init__.py | 0 kdb-bot/src/bot_api/model/discord/__init__.py | 0 .../src/bot_api/model/discord/server_dto.py | 49 +++++++++++++++++++ .../src/bot_api/service/discord_service.py | 23 +++++++++ .../bot_api/transformer/server_transformer.py | 19 +++++++ 8 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 kdb-bot/src/bot_api/controller/discord/__init__.py create mode 100644 kdb-bot/src/bot_api/controller/discord/server_controller.py create mode 100644 kdb-bot/src/bot_api/event/__init__.py create mode 100644 kdb-bot/src/bot_api/model/discord/__init__.py create mode 100644 kdb-bot/src/bot_api/model/discord/server_dto.py create mode 100644 kdb-bot/src/bot_api/service/discord_service.py create mode 100644 kdb-bot/src/bot_api/transformer/server_transformer.py diff --git a/kdb-bot/src/bot/config/feature-flags.json b/kdb-bot/src/bot/config/feature-flags.json index 2d214f7f3e..68bf6e002c 100644 --- a/kdb-bot/src/bot/config/feature-flags.json +++ b/kdb-bot/src/bot/config/feature-flags.json @@ -10,7 +10,6 @@ "DatabaseModule": true, "ModeratorModule": true, "PermissionModule": true, - "PresenceModule": true, - "ApiOnly": true + "PresenceModule": true } } diff --git a/kdb-bot/src/bot_api/controller/discord/__init__.py b/kdb-bot/src/bot_api/controller/discord/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-bot/src/bot_api/controller/discord/server_controller.py b/kdb-bot/src/bot_api/controller/discord/server_controller.py new file mode 100644 index 0000000000..957624a465 --- /dev/null +++ b/kdb-bot/src/bot_api/controller/discord/server_controller.py @@ -0,0 +1,39 @@ +from cpl_core.configuration import ConfigurationABC +from cpl_core.environment import ApplicationEnvironmentABC +from cpl_core.mailing import EMailClientABC, EMailClientSettings +from cpl_translation import TranslatePipe +from flask import Response, jsonify + +from bot_api.api import Api +from bot_api.logging.api_logger import ApiLogger +from bot_api.route.route import Route +from bot_api.service.discord_service import DiscordService + + +class ServerController: + BasePath = f'/api/discord/server' + + def __init__( + self, + config: ConfigurationABC, + env: ApplicationEnvironmentABC, + logger: ApiLogger, + t: TranslatePipe, + api: Api, + mail_settings: EMailClientSettings, + mailer: EMailClientABC, + discord_service: DiscordService + ): + self._config = config + self._env = env + self._logger = logger + self._t = t + self._api = api + self._mail_settings = mail_settings + self._mailer = mailer + self._discord_service = discord_service + + @Route.get(f'{BasePath}/servers') + @Route.authorize + async def get_all_servers(self) -> Response: + return jsonify(self._discord_service.get_all_servers().select(lambda x: x.to_dict())) diff --git a/kdb-bot/src/bot_api/event/__init__.py b/kdb-bot/src/bot_api/event/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-bot/src/bot_api/model/discord/__init__.py b/kdb-bot/src/bot_api/model/discord/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-bot/src/bot_api/model/discord/server_dto.py b/kdb-bot/src/bot_api/model/discord/server_dto.py new file mode 100644 index 0000000000..e7115dd231 --- /dev/null +++ b/kdb-bot/src/bot_api/model/discord/server_dto.py @@ -0,0 +1,49 @@ +from bot_api.abc.dto_abc import DtoABC + + +class ServerDTO(DtoABC): + + def __init__( + self, + server_id: int, + discord_id: int, + name: str, + member_count: int + + ): + DtoABC.__init__(self) + + self._server_id = server_id + self._discord_id = discord_id + self._name = name + self._member_count = member_count + + @property + def server_id(self) -> int: + return self._server_id + + @property + def discord_id(self) -> int: + return self._discord_id + + @property + def name(self) -> str: + return self._name + + @property + def member_count(self) -> int: + return self._member_count + + def from_dict(self, values: dict): + self._server_id = int(values['serverId']) + self._discord_id = int(values['discordId']) + self._name = values['name'] + self._member_count = int(values['memberCount']) + + def to_dict(self) -> dict: + return { + 'serverId': self._server_id, + 'discordId': self._discord_id, + 'name': self._name, + 'memberCount': self._member_count, + } diff --git a/kdb-bot/src/bot_api/service/discord_service.py b/kdb-bot/src/bot_api/service/discord_service.py new file mode 100644 index 0000000000..448d4d7f18 --- /dev/null +++ b/kdb-bot/src/bot_api/service/discord_service.py @@ -0,0 +1,23 @@ +from cpl_discord.service import DiscordBotServiceABC +from cpl_query.extension import List + +from bot_api.model.discord.server_dto import ServerDTO +from bot_api.transformer.server_transformer import ServerTransformer +from bot_data.abc.server_repository_abc import ServerRepositoryABC + + +class DiscordService: + + def __init__( + self, + bot: DiscordBotServiceABC, + servers: ServerRepositoryABC, + ): + self._bot = bot + self._servers = servers + + def get_all_servers(self) -> List[ServerDTO]: + servers = self._servers.get_servers().select() + return servers.select( + lambda x: ServerTransformer.to_dto(x, self._bot.get_guild(x.discord_server_id).name, self._bot.get_guild(x.discord_server_id).member_count) + ) diff --git a/kdb-bot/src/bot_api/transformer/server_transformer.py b/kdb-bot/src/bot_api/transformer/server_transformer.py new file mode 100644 index 0000000000..920fd506d0 --- /dev/null +++ b/kdb-bot/src/bot_api/transformer/server_transformer.py @@ -0,0 +1,19 @@ +from bot_api.abc.transformer_abc import TransformerABC +from bot_api.model.discord.server_dto import ServerDTO +from bot_data.model.server import Server + + +class ServerTransformer(TransformerABC): + + @staticmethod + def to_db(dto: ServerDTO) -> Server: + return Server(dto.discord_id) + + @staticmethod + def to_dto(db: Server, name: str, member_count: int) -> ServerDTO: + return ServerDTO( + db.server_id, + db.discord_server_id, + name, + member_count, + ) From dfcc516389a0a981931e640ed92bc4a83176fc42 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Mon, 17 Oct 2022 13:53:37 +0200 Subject: [PATCH 035/102] Added role check to authorization #72 --- kdb-bot/src/bot_api/api_module.py | 4 +++ .../src/bot_api/controller/auth_controller.py | 15 ++++++----- .../controller/discord/server_controller.py | 3 ++- .../exception/service_error_code_enum.py | 1 + kdb-bot/src/bot_api/route/route.py | 26 +++++++++++++++++-- kdb-bot/src/bot_api/service/auth_service.py | 4 ++- .../transformer/auth_user_transformer.py | 2 +- 7 files changed, 43 insertions(+), 12 deletions(-) diff --git a/kdb-bot/src/bot_api/api_module.py b/kdb-bot/src/bot_api/api_module.py index d6d659ecba..0a9446ad5d 100644 --- a/kdb-bot/src/bot_api/api_module.py +++ b/kdb-bot/src/bot_api/api_module.py @@ -11,10 +11,12 @@ from flask import Flask from bot_api.abc.auth_service_abc import AuthServiceABC from bot_api.api import Api from bot_api.api_thread import ApiThread +from bot_api.controller.discord.server_controller import ServerController from bot_api.controller.gui_controller import GuiController from bot_api.controller.auth_controller import AuthController from bot_api.event.bot_api_on_ready_event import BotApiOnReadyEvent from bot_api.service.auth_service import AuthService +from bot_api.service.discord_service import DiscordService from bot_core.abc.module_abc import ModuleABC from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum @@ -41,6 +43,8 @@ class ApiModule(ModuleABC): services.add_transient(AuthServiceABC, AuthService) services.add_transient(AuthController) services.add_transient(GuiController) + services.add_transient(DiscordService) + services.add_transient(ServerController) # cpl-discord self._dc.add_event(DiscordEventTypesEnum.on_ready.value, BotApiOnReadyEvent) diff --git a/kdb-bot/src/bot_api/controller/auth_controller.py b/kdb-bot/src/bot_api/controller/auth_controller.py index a23d490dff..78a17e79e6 100644 --- a/kdb-bot/src/bot_api/controller/auth_controller.py +++ b/kdb-bot/src/bot_api/controller/auth_controller.py @@ -15,6 +15,7 @@ from bot_api.model.auth_user_dto import AuthUserDTO from bot_api.model.token_dto import TokenDTO from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO from bot_api.route.route import Route +from bot_data.model.auth_role_enum import AuthRoleEnum class AuthController: @@ -41,13 +42,13 @@ class AuthController: self._auth_service = auth_service @Route.get(f'{BasePath}/users') - @Route.authorize + @Route.authorize(role=AuthRoleEnum.admin) async def get_all_users(self) -> Response: result = await self._auth_service.get_all_auth_users_async() return jsonify(result.select(lambda x: x.to_dict())) @Route.post(f'{BasePath}/users/get/filtered') - @Route.authorize + @Route.authorize(role=AuthRoleEnum.admin) async def get_filtered_users(self) -> Response: dto: AuthUserSelectCriteria = JSONProcessor.process(AuthUserSelectCriteria, request.get_json(force=True, silent=True)) result = await self._auth_service.get_filtered_auth_users_async(dto) @@ -55,13 +56,13 @@ class AuthController: return jsonify(result.to_dict()) @Route.get(f'{BasePath}/users/get/') - @Route.authorize + @Route.authorize(role=AuthRoleEnum.admin) async def get_user_from_email(self, email: str) -> Response: result = await self._auth_service.get_auth_user_by_email_async(email) return jsonify(result.to_dict()) @Route.get(f'{BasePath}/users/find/') - @Route.authorize + @Route.authorize(role=AuthRoleEnum.admin) async def find_user_from_email(self, email: str) -> Response: result = await self._auth_service.find_auth_user_by_email_async(email) return jsonify(result.to_dict()) @@ -109,7 +110,7 @@ class AuthController: return '', 200 @Route.post(f'{BasePath}/update-user-as-admin') - @Route.authorize + @Route.authorize(role=AuthRoleEnum.admin) async def update_user_as_admin(self): dto: UpdateAuthUserDTO = JSONProcessor.process(UpdateAuthUserDTO, request.get_json(force=True, silent=True)) await self._auth_service.update_user_as_admin_async(dto) @@ -129,14 +130,14 @@ class AuthController: return '', 200 @Route.post(f'{BasePath}/delete-user') - @Route.authorize + @Route.authorize(role=AuthRoleEnum.admin) async def delete_user(self): dto: AuthUserDTO = JSONProcessor.process(AuthUserDTO, request.get_json(force=True, silent=True)) await self._auth_service.delete_auth_user_async(dto) return '', 200 @Route.post(f'{BasePath}/delete-user-by-mail/') - @Route.authorize + @Route.authorize(role=AuthRoleEnum.admin) async def delete_user_by_mail(self, email: str): await self._auth_service.delete_auth_user_by_email_async(email) return '', 200 diff --git a/kdb-bot/src/bot_api/controller/discord/server_controller.py b/kdb-bot/src/bot_api/controller/discord/server_controller.py index 957624a465..59b7f531b8 100644 --- a/kdb-bot/src/bot_api/controller/discord/server_controller.py +++ b/kdb-bot/src/bot_api/controller/discord/server_controller.py @@ -8,6 +8,7 @@ from bot_api.api import Api from bot_api.logging.api_logger import ApiLogger from bot_api.route.route import Route from bot_api.service.discord_service import DiscordService +from bot_data.model.auth_role_enum import AuthRoleEnum class ServerController: @@ -34,6 +35,6 @@ class ServerController: self._discord_service = discord_service @Route.get(f'{BasePath}/servers') - @Route.authorize + @Route.authorize(role=AuthRoleEnum.admin) async def get_all_servers(self) -> Response: return jsonify(self._discord_service.get_all_servers().select(lambda x: x.to_dict())) diff --git a/kdb-bot/src/bot_api/exception/service_error_code_enum.py b/kdb-bot/src/bot_api/exception/service_error_code_enum.py index 7b19aeb18c..5848bf3374 100644 --- a/kdb-bot/src/bot_api/exception/service_error_code_enum.py +++ b/kdb-bot/src/bot_api/exception/service_error_code_enum.py @@ -21,3 +21,4 @@ class ServiceErrorCode(Enum): MailError = 10 Unauthorized = 11 + Forbidden = 12 diff --git a/kdb-bot/src/bot_api/route/route.py b/kdb-bot/src/bot_api/route/route.py index ce8826bcd1..26bdad2b80 100644 --- a/kdb-bot/src/bot_api/route/route.py +++ b/kdb-bot/src/bot_api/route/route.py @@ -1,5 +1,6 @@ +import functools from functools import wraps -from typing import Optional +from typing import Optional, Callable from flask import request, jsonify from flask_cors import cross_origin @@ -9,6 +10,7 @@ from bot_api.exception.service_error_code_enum import ServiceErrorCode from bot_api.exception.service_exception import ServiceException from bot_api.model.error_dto import ErrorDTO from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC +from bot_data.model.auth_role_enum import AuthRoleEnum class Route: @@ -23,7 +25,10 @@ class Route: cls._auth = auth @classmethod - def authorize(cls, f): + def authorize(cls, f: Callable = None, role: AuthRoleEnum = None): + if f is None: + return functools.partial(cls.authorize, role=role) + @wraps(f) async def decorator(*args, **kwargs): token = None @@ -46,6 +51,23 @@ class Route: error = ErrorDTO(ex.error_code, ex.message) return jsonify(error.to_dict()), 401 + token = cls._auth.decode_token(token) + if token is None or 'email' not in token: + ex = ServiceException(ServiceErrorCode.Unauthorized, f'Token invalid') + error = ErrorDTO(ex.error_code, ex.message) + return jsonify(error.to_dict()), 401 + + user = cls._auth_users.get_auth_user_by_email(token['email']) + if user is None: + ex = ServiceException(ServiceErrorCode.Unauthorized, f'Token invalid') + error = ErrorDTO(ex.error_code, ex.message) + return jsonify(error.to_dict()), 401 + + if role is not None and user.auth_role.value < role.value: + ex = ServiceException(ServiceErrorCode.Unauthorized, f'Role {role} required') + error = ErrorDTO(ex.error_code, ex.message) + return jsonify(error.to_dict()), 403 + return await f(*args, **kwargs) return decorator diff --git a/kdb-bot/src/bot_api/service/auth_service.py b/kdb-bot/src/bot_api/service/auth_service.py index e1e4a2b943..540f5d1409 100644 --- a/kdb-bot/src/bot_api/service/auth_service.py +++ b/kdb-bot/src/bot_api/service/auth_service.py @@ -27,6 +27,8 @@ from bot_api.transformer.auth_user_transformer import AuthUserTransformer as AUT from bot_data.abc.auth_user_repository_abc import AuthUserRepositoryABC from bot_data.model.auth_user import AuthUser +_email_regex = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b' + class AuthService(AuthServiceABC): @@ -65,7 +67,7 @@ class AuthService(AuthServiceABC): @staticmethod def _is_email_valid(email: str) -> bool: - if re.match(re.compile(r'^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$'), email) is not None: + if re.fullmatch(_email_regex, email) is not None: return True return False diff --git a/kdb-bot/src/bot_api/transformer/auth_user_transformer.py b/kdb-bot/src/bot_api/transformer/auth_user_transformer.py index 3f84a9399a..3506611aad 100644 --- a/kdb-bot/src/bot_api/transformer/auth_user_transformer.py +++ b/kdb-bot/src/bot_api/transformer/auth_user_transformer.py @@ -19,7 +19,7 @@ class AuthUserTransformer(TransformerABC): None, None, datetime.now(tz=timezone.utc), - AuthRoleEnum.normal if dto.auth_role is None else dto.auth_role, + AuthRoleEnum.normal if dto.auth_role is None else AuthRoleEnum(dto.auth_role), id=0 if dto.id is None else dto.id ) From d7a0706e0c333a395f539b3e911feffe7494f755 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Mon, 17 Oct 2022 16:07:33 +0200 Subject: [PATCH 036/102] Improved get server logic #72 --- kdb-bot/src/bot_api/abc/auth_service_abc.py | 7 ++++ .../controller/discord/server_controller.py | 11 +++++- kdb-bot/src/bot_api/model/auth_user_dto.py | 12 +++++++ kdb-bot/src/bot_api/service/auth_service.py | 32 +++++++++++++++++ .../src/bot_api/service/discord_service.py | 34 +++++++++++++++++-- .../transformer/auth_user_transformer.py | 6 ++-- .../src/bot_data/abc/user_repository_abc.py | 3 ++ .../src/bot_data/migration/api_migration.py | 4 ++- kdb-bot/src/bot_data/model/auth_user.py | 13 +++++++ .../service/auth_user_repository_service.py | 1 + .../service/user_repository_service.py | 15 ++++++++ 11 files changed, 132 insertions(+), 6 deletions(-) diff --git a/kdb-bot/src/bot_api/abc/auth_service_abc.py b/kdb-bot/src/bot_api/abc/auth_service_abc.py index 3a006a0dcf..cd54128dda 100644 --- a/kdb-bot/src/bot_api/abc/auth_service_abc.py +++ b/kdb-bot/src/bot_api/abc/auth_service_abc.py @@ -1,4 +1,5 @@ from abc import ABC, abstractmethod +from typing import Optional from cpl_query.extension import List @@ -23,6 +24,12 @@ class AuthServiceABC(ABC): @abstractmethod def decode_token(self, token: str) -> dict: pass + @abstractmethod + def get_decoded_token_from_request(self) -> dict: pass + + @abstractmethod + def find_decoded_token_from_request(self) -> Optional[dict]: pass + @abstractmethod async def get_all_auth_users_async(self) -> List[AuthUserDTO]: pass diff --git a/kdb-bot/src/bot_api/controller/discord/server_controller.py b/kdb-bot/src/bot_api/controller/discord/server_controller.py index 59b7f531b8..394338699e 100644 --- a/kdb-bot/src/bot_api/controller/discord/server_controller.py +++ b/kdb-bot/src/bot_api/controller/discord/server_controller.py @@ -37,4 +37,13 @@ class ServerController: @Route.get(f'{BasePath}/servers') @Route.authorize(role=AuthRoleEnum.admin) async def get_all_servers(self) -> Response: - return jsonify(self._discord_service.get_all_servers().select(lambda x: x.to_dict())) + result = await self._discord_service.get_all_servers() + result = result.select(lambda x: x.to_dict()) + return jsonify(result) + + @Route.get(f'{BasePath}/servers-by-user') + @Route.authorize + async def get_all_servers_by_user(self) -> Response: + result = await self._discord_service.get_all_servers_by_user() + result = result.select(lambda x: x.to_dict()) + return jsonify(result) diff --git a/kdb-bot/src/bot_api/model/auth_user_dto.py b/kdb-bot/src/bot_api/model/auth_user_dto.py index 4fb5339455..8d42e1fad6 100644 --- a/kdb-bot/src/bot_api/model/auth_user_dto.py +++ b/kdb-bot/src/bot_api/model/auth_user_dto.py @@ -15,6 +15,7 @@ class AuthUserDTO(DtoABC): password: str, confirmation_id: Optional[str], auth_role: AuthRoleEnum, + user_id: Optional[int], ): DtoABC.__init__(self) @@ -25,6 +26,7 @@ class AuthUserDTO(DtoABC): self._password = password self._is_confirmed = confirmation_id is None self._auth_role = auth_role + self._user_id = user_id @property def id(self) -> int: @@ -78,6 +80,14 @@ class AuthUserDTO(DtoABC): def auth_role(self, value: AuthRoleEnum): self._auth_role = value + @property + def user_id(self) -> Optional[int]: + return self._user_id + + @user_id.setter + def user_id(self, value: Optional[int]): + self._user_id = value + def from_dict(self, values: dict): self._id = values['id'] self._first_name = values['firstName'] @@ -86,6 +96,7 @@ class AuthUserDTO(DtoABC): self._password = values['password'] self._is_confirmed = values['isConfirmed'] self._auth_role = values['authRole'] + self._user_id = values['userId'] def to_dict(self) -> dict: return { @@ -96,4 +107,5 @@ class AuthUserDTO(DtoABC): 'password': self._password, 'isConfirmed': self._is_confirmed, 'authRole': self._auth_role.value, + 'userId': self._user_id, } diff --git a/kdb-bot/src/bot_api/service/auth_service.py b/kdb-bot/src/bot_api/service/auth_service.py index 540f5d1409..b2056530d7 100644 --- a/kdb-bot/src/bot_api/service/auth_service.py +++ b/kdb-bot/src/bot_api/service/auth_service.py @@ -9,6 +9,7 @@ from cpl_core.database.context import DatabaseContextABC from cpl_core.mailing import EMailClientABC, EMail from cpl_query.extension import List from cpl_translation import TranslatePipe +from flask import request from bot_api.abc.auth_service_abc import AuthServiceABC from bot_api.configuration.authentication_settings import AuthenticationSettings @@ -96,6 +97,37 @@ class AuthService(AuthServiceABC): algorithms=['HS256'] ) + def get_decoded_token_from_request(self) -> dict: + token = None + if 'Authorization' in request.headers: + bearer = request.headers.get('Authorization') + token = bearer.split()[1] + + if token is None: + raise ServiceException(ServiceErrorCode.Unauthorized, f'Token not set') + + return jwt.decode( + token, + key=self._auth_settings.secret_key, + issuer=self._auth_settings.issuer, + audience=self._auth_settings.audience, + algorithms=['HS256'] + ) + + def find_decoded_token_from_request(self) -> Optional[dict]: + token = None + if 'Authorization' in request.headers: + bearer = request.headers.get('Authorization') + token = bearer.split()[1] + + return jwt.decode( + token, + key=self._auth_settings.secret_key, + issuer=self._auth_settings.issuer, + audience=self._auth_settings.audience, + algorithms=['HS256'] + ) if token is not None else None + def _create_and_save_refresh_token(self, user: AuthUser) -> str: token = str(uuid.uuid4()) user.refresh_token = token diff --git a/kdb-bot/src/bot_api/service/discord_service.py b/kdb-bot/src/bot_api/service/discord_service.py index 448d4d7f18..e6b3056c4e 100644 --- a/kdb-bot/src/bot_api/service/discord_service.py +++ b/kdb-bot/src/bot_api/service/discord_service.py @@ -1,9 +1,18 @@ +from typing import Optional + from cpl_discord.service import DiscordBotServiceABC from cpl_query.extension import List +from flask import jsonify +from bot_api.abc.auth_service_abc import AuthServiceABC +from bot_api.exception.service_error_code_enum import ServiceErrorCode +from bot_api.exception.service_exception import ServiceException from bot_api.model.discord.server_dto import ServerDTO +from bot_api.model.error_dto import ErrorDTO from bot_api.transformer.server_transformer import ServerTransformer from bot_data.abc.server_repository_abc import ServerRepositoryABC +from bot_data.abc.user_repository_abc import UserRepositoryABC +from bot_data.model.auth_role_enum import AuthRoleEnum class DiscordService: @@ -12,12 +21,33 @@ class DiscordService: self, bot: DiscordBotServiceABC, servers: ServerRepositoryABC, + auth: AuthServiceABC, + users: UserRepositoryABC, ): self._bot = bot self._servers = servers + self._auth = auth + self._users = users + + async def get_all_servers(self) -> List[ServerDTO]: + servers = self._servers.get_servers() + return servers.select( + lambda x: ServerTransformer.to_dto(x, self._bot.get_guild(x.discord_server_id).name, self._bot.get_guild(x.discord_server_id).member_count) + ) + + async def get_all_servers_by_user(self) -> List[ServerDTO]: + token = self._auth.get_decoded_token_from_request() + if token is None or 'email' not in token or 'role' not in token: + raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid') + + role = AuthRoleEnum(token['role']) + if role == AuthRoleEnum.admin: + servers = self._servers.get_servers() + else: + user = await self._auth.find_auth_user_by_email_async(token['email']) + user_from_db = self._users.find_user_by_id(0 if user.user_id is None else user.user_id) + servers = self._servers.get_servers().where(lambda x: user_from_db is not None and x.server_id == user_from_db.server.server_id) - def get_all_servers(self) -> List[ServerDTO]: - servers = self._servers.get_servers().select() return servers.select( lambda x: ServerTransformer.to_dto(x, self._bot.get_guild(x.discord_server_id).name, self._bot.get_guild(x.discord_server_id).member_count) ) diff --git a/kdb-bot/src/bot_api/transformer/auth_user_transformer.py b/kdb-bot/src/bot_api/transformer/auth_user_transformer.py index 3506611aad..b5608e2376 100644 --- a/kdb-bot/src/bot_api/transformer/auth_user_transformer.py +++ b/kdb-bot/src/bot_api/transformer/auth_user_transformer.py @@ -9,7 +9,7 @@ from bot_data.model.auth_user import AuthUser class AuthUserTransformer(TransformerABC): @staticmethod - def to_db(dto: AuthUser) -> AuthUser: + def to_db(dto: AuthUserDTO) -> AuthUser: return AuthUser( dto.first_name, dto.last_name, @@ -20,6 +20,7 @@ class AuthUserTransformer(TransformerABC): None, datetime.now(tz=timezone.utc), AuthRoleEnum.normal if dto.auth_role is None else AuthRoleEnum(dto.auth_role), + dto.user_id, id=0 if dto.id is None else dto.id ) @@ -32,5 +33,6 @@ class AuthUserTransformer(TransformerABC): db.email, db.password, db.confirmation_id, - db.auth_role + db.auth_role, + db.user_id ) diff --git a/kdb-bot/src/bot_data/abc/user_repository_abc.py b/kdb-bot/src/bot_data/abc/user_repository_abc.py index ff7f625445..12878b6fd6 100644 --- a/kdb-bot/src/bot_data/abc/user_repository_abc.py +++ b/kdb-bot/src/bot_data/abc/user_repository_abc.py @@ -16,6 +16,9 @@ class UserRepositoryABC(ABC): @abstractmethod def get_user_by_id(self, id: int) -> User: pass + + @abstractmethod + def find_user_by_id(self, id: int) -> Optional[User]: pass @abstractmethod def get_users_by_discord_id(self, discord_id: int) -> List[User]: pass diff --git a/kdb-bot/src/bot_data/migration/api_migration.py b/kdb-bot/src/bot_data/migration/api_migration.py index 80754c88a5..6860ae1440 100644 --- a/kdb-bot/src/bot_data/migration/api_migration.py +++ b/kdb-bot/src/bot_data/migration/api_migration.py @@ -28,9 +28,11 @@ class ApiMigration(MigrationABC): `ForgotPasswordId` VARCHAR(255) DEFAULT NULL, `RefreshTokenExpiryTime` DATETIME(6) NOT NULL, `AuthRole` INT NOT NULL DEFAULT '0', + `UserId` BIGINT NOT NULL DEFAULT '0', `CreatedOn` DATETIME(6) NOT NULL, `LastModifiedOn` DATETIME(6) NOT NULL, - PRIMARY KEY(`Id`) + PRIMARY KEY(`Id`), + FOREIGN KEY (`UserId`) REFERENCES `Users`(`UserId`) ) """) ) diff --git a/kdb-bot/src/bot_data/model/auth_user.py b/kdb-bot/src/bot_data/model/auth_user.py index 26ba09a868..fe92ad1eb9 100644 --- a/kdb-bot/src/bot_data/model/auth_user.py +++ b/kdb-bot/src/bot_data/model/auth_user.py @@ -19,6 +19,7 @@ class AuthUser(TableABC): forgot_password_id: Optional[str], refresh_token_expire_time: datetime, auth_role: AuthRoleEnum, + user_id: Optional[int], created_at: datetime = None, modified_at: datetime = None, id=0 @@ -34,6 +35,7 @@ class AuthUser(TableABC): self._refresh_token_expire_time = refresh_token_expire_time self._auth_role_id = auth_role + self._user_id = user_id TableABC.__init__(self) self._created_at = created_at if created_at is not None else self._created_at @@ -115,6 +117,14 @@ class AuthUser(TableABC): def auth_role(self, value: AuthRoleEnum): self._auth_role_id = value + @property + def user_id(self) -> Optional[int]: + return self._user_id + + @user_id.setter + def user_id(self, value: Optional[int]): + self._user_id = value + @staticmethod def get_select_all_string() -> str: return str(f""" @@ -163,6 +173,7 @@ class AuthUser(TableABC): `ForgotPasswordId`, `RefreshTokenExpiryTime`, `AuthRole`, + `UserId`, `CreatedOn`, `LastModifiedOn` ) VALUES ( @@ -176,6 +187,7 @@ class AuthUser(TableABC): '{"NULL" if self._forgot_password_id is None else self._forgot_password_id}', '{self._refresh_token_expire_time}', {self._auth_role_id.value}, + {"NULL" if self._user_id is None else self._user_id} '{self._created_at}', '{self._modified_at}' ) @@ -194,6 +206,7 @@ class AuthUser(TableABC): `ForgotPasswordId` = '{"NULL" if self._forgot_password_id is None else self._forgot_password_id}', `RefreshTokenExpiryTime` = '{self._refresh_token_expire_time}', `AuthRole` = {self._auth_role_id.value}, + `UserId` = {"NULL" if self._user_id is None else self._user_id}, `LastModifiedOn` = '{self._modified_at}' WHERE `AuthUsers`.`Id` = {self._auth_user_id}; """) diff --git a/kdb-bot/src/bot_data/service/auth_user_repository_service.py b/kdb-bot/src/bot_data/service/auth_user_repository_service.py index 4918b26980..c8fee7b4aa 100644 --- a/kdb-bot/src/bot_data/service/auth_user_repository_service.py +++ b/kdb-bot/src/bot_data/service/auth_user_repository_service.py @@ -37,6 +37,7 @@ class AuthUserRepositoryService(AuthUserRepositoryABC): self._get_value_from_result(result[7]), self._get_value_from_result(result[8]), AuthRoleEnum(self._get_value_from_result(result[9])), + self._get_value_from_result(result[10]), id=self._get_value_from_result(result[0]) ) diff --git a/kdb-bot/src/bot_data/service/user_repository_service.py b/kdb-bot/src/bot_data/service/user_repository_service.py index f2543e5dd7..83f9862778 100644 --- a/kdb-bot/src/bot_data/service/user_repository_service.py +++ b/kdb-bot/src/bot_data/service/user_repository_service.py @@ -44,6 +44,21 @@ class UserRepositoryService(UserRepositoryABC): self._servers.get_server_by_id(result[3]), id=result[0] ) + + def find_user_by_id(self, id: int) -> Optional[User]: + self._logger.trace(__name__, f'Send SQL command: {User.get_select_by_id_string(id)}') + result = self._context.select(User.get_select_by_id_string(id)) + if result is None or len(result) == 0: + return None + + result = result[0] + + return User( + result[1], + result[2], + self._servers.get_server_by_id(result[3]), + id=result[0] + ) def get_users_by_discord_id(self, discord_id: int) -> List[User]: users = List(User) From 3d17bb7703042236f58272be2beba8c0d4a9829e Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Mon, 17 Oct 2022 16:22:09 +0200 Subject: [PATCH 037/102] Added get filtered servers #72 --- .../controller/discord/server_controller.py | 12 ++++++++- .../src/bot_api/filter/discord/__init__.py | 0 .../filter/discord/server_select_criteria.py | 17 +++++++++++++ .../discord/server_filtered_result_dto.py | 21 ++++++++++++++++ .../src/bot_api/service/discord_service.py | 25 +++++++++++++++++++ .../src/bot_data/abc/server_repository_abc.py | 5 ++++ .../service/server_repository_service.py | 25 +++++++++++++++++++ 7 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 kdb-bot/src/bot_api/filter/discord/__init__.py create mode 100644 kdb-bot/src/bot_api/filter/discord/server_select_criteria.py create mode 100644 kdb-bot/src/bot_api/model/discord/server_filtered_result_dto.py diff --git a/kdb-bot/src/bot_api/controller/discord/server_controller.py b/kdb-bot/src/bot_api/controller/discord/server_controller.py index 394338699e..35a3fa9c96 100644 --- a/kdb-bot/src/bot_api/controller/discord/server_controller.py +++ b/kdb-bot/src/bot_api/controller/discord/server_controller.py @@ -2,9 +2,11 @@ from cpl_core.configuration import ConfigurationABC from cpl_core.environment import ApplicationEnvironmentABC from cpl_core.mailing import EMailClientABC, EMailClientSettings from cpl_translation import TranslatePipe -from flask import Response, jsonify +from flask import Response, jsonify, request from bot_api.api import Api +from bot_api.filter.discord.server_select_criteria import ServerSelectCriteria +from bot_api.json_processor import JSONProcessor from bot_api.logging.api_logger import ApiLogger from bot_api.route.route import Route from bot_api.service.discord_service import DiscordService @@ -41,6 +43,14 @@ class ServerController: result = result.select(lambda x: x.to_dict()) return jsonify(result) + @Route.get(f'{BasePath}/servers/get/filtered') + @Route.authorize + async def get_all_servers_by_user(self) -> Response: + dto: ServerSelectCriteria = JSONProcessor.process(ServerSelectCriteria, request.get_json(force=True, silent=True)) + result = await self._discord_service.get_filtered_servers_async(dto) + result.result = result.result.select(lambda x: x.to_dict()) + return jsonify(result.to_dict()) + @Route.get(f'{BasePath}/servers-by-user') @Route.authorize async def get_all_servers_by_user(self) -> Response: diff --git a/kdb-bot/src/bot_api/filter/discord/__init__.py b/kdb-bot/src/bot_api/filter/discord/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-bot/src/bot_api/filter/discord/server_select_criteria.py b/kdb-bot/src/bot_api/filter/discord/server_select_criteria.py new file mode 100644 index 0000000000..f1454a8c95 --- /dev/null +++ b/kdb-bot/src/bot_api/filter/discord/server_select_criteria.py @@ -0,0 +1,17 @@ +from bot_api.abc.select_criteria_abc import SelectCriteriaABC + + +class ServerSelectCriteria(SelectCriteriaABC): + + def __init__( + self, + page_index: int, + page_size: int, + sort_direction: str, + sort_column: str, + + name: str, + ): + SelectCriteriaABC.__init__(self, page_index, page_size, sort_direction, sort_column) + + self.name = name diff --git a/kdb-bot/src/bot_api/model/discord/server_filtered_result_dto.py b/kdb-bot/src/bot_api/model/discord/server_filtered_result_dto.py new file mode 100644 index 0000000000..eceb642ca0 --- /dev/null +++ b/kdb-bot/src/bot_api/model/discord/server_filtered_result_dto.py @@ -0,0 +1,21 @@ +from cpl_query.extension import List + +from bot_api.abc.dto_abc import DtoABC +from bot_data.filtered_result import FilteredResult + + +class ServerFilteredResultDTO(DtoABC, FilteredResult): + + def __init__(self, result: List = None, total_count: int = 0): + DtoABC.__init__(self) + FilteredResult.__init__(self, result, total_count) + + def from_dict(self, values: dict): + self._result = values['servers'] + self._total_count = values['totalCount'] + + def to_dict(self) -> dict: + return { + 'servers': self.result, + 'totalCount': self.total_count + } diff --git a/kdb-bot/src/bot_api/service/discord_service.py b/kdb-bot/src/bot_api/service/discord_service.py index e6b3056c4e..e00e5b8486 100644 --- a/kdb-bot/src/bot_api/service/discord_service.py +++ b/kdb-bot/src/bot_api/service/discord_service.py @@ -7,7 +7,9 @@ from flask import jsonify from bot_api.abc.auth_service_abc import AuthServiceABC from bot_api.exception.service_error_code_enum import ServiceErrorCode from bot_api.exception.service_exception import ServiceException +from bot_api.filter.discord.server_select_criteria import ServerSelectCriteria from bot_api.model.discord.server_dto import ServerDTO +from bot_api.model.discord.server_filtered_result_dto import ServerFilteredResultDTO from bot_api.model.error_dto import ErrorDTO from bot_api.transformer.server_transformer import ServerTransformer from bot_data.abc.server_repository_abc import ServerRepositoryABC @@ -35,6 +37,29 @@ class DiscordService: lambda x: ServerTransformer.to_dto(x, self._bot.get_guild(x.discord_server_id).name, self._bot.get_guild(x.discord_server_id).member_count) ) + async def get_filtered_servers_async(self, criteria: ServerSelectCriteria) -> ServerFilteredResultDTO: + token = self._auth.get_decoded_token_from_request() + if token is None or 'email' not in token or 'role' not in token: + raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid') + + role = AuthRoleEnum(token['role']) + role = AuthRoleEnum(token['role']) + filtered_result = self._servers.get_filtered_servers(criteria) + servers = filtered_result.result + if role != AuthRoleEnum.admin: + user = await self._auth.find_auth_user_by_email_async(token['email']) + user_from_db = self._users.find_user_by_id(0 if user.user_id is None else user.user_id) + servers = servers.where(lambda x: user_from_db is not None and x.server_id == user_from_db.server.server_id) + + result = servers.select( + lambda x: ServerTransformer.to_dto(x, self._bot.get_guild(x.discord_server_id).name, self._bot.get_guild(x.discord_server_id).member_count) + ) + + return ServerFilteredResultDTO( + List(ServerDTO, result), + servers.total_count + ) + async def get_all_servers_by_user(self) -> List[ServerDTO]: token = self._auth.get_decoded_token_from_request() if token is None or 'email' not in token or 'role' not in token: diff --git a/kdb-bot/src/bot_data/abc/server_repository_abc.py b/kdb-bot/src/bot_data/abc/server_repository_abc.py index d1ab13fe63..f3eea75a9d 100644 --- a/kdb-bot/src/bot_data/abc/server_repository_abc.py +++ b/kdb-bot/src/bot_data/abc/server_repository_abc.py @@ -3,6 +3,8 @@ from typing import Optional from cpl_query.extension import List +from bot_api.filter.discord.server_select_criteria import ServerSelectCriteria +from bot_data.filtered_result import FilteredResult from bot_data.model.server import Server @@ -13,6 +15,9 @@ class ServerRepositoryABC(ABC): @abstractmethod def get_servers(self) -> List[Server]: pass + + @abstractmethod + def get_filtered_servers(self, criteria: ServerSelectCriteria) -> FilteredResult: pass @abstractmethod def get_server_by_id(self, id: int) -> Server: pass diff --git a/kdb-bot/src/bot_data/service/server_repository_service.py b/kdb-bot/src/bot_data/service/server_repository_service.py index 728d2bc679..37b2918e2c 100644 --- a/kdb-bot/src/bot_data/service/server_repository_service.py +++ b/kdb-bot/src/bot_data/service/server_repository_service.py @@ -3,8 +3,10 @@ from typing import Optional from cpl_core.database.context import DatabaseContextABC from cpl_query.extension import List +from bot_api.filter.discord.server_select_criteria import ServerSelectCriteria from bot_core.logging.database_logger import DatabaseLogger from bot_data.abc.server_repository_abc import ServerRepositoryABC +from bot_data.filtered_result import FilteredResult from bot_data.model.server import Server @@ -28,6 +30,29 @@ class ServerRepositoryService(ServerRepositoryABC): return servers + def get_filtered_servers(self, criteria: ServerSelectCriteria) -> FilteredResult: + servers = self.get_servers() + self._logger.trace(__name__, f'Send SQL command: {Server.get_select_all_string()}') + query = servers + + if criteria.name is not None and criteria.name != '': + query = query.where(lambda x: criteria.name in x.first_name or x.first_name == criteria.name) + + # sort + if criteria.sort_column is not None and criteria.sort_column != '' and criteria.sort_direction is not None and criteria.sort_direction: + crit_sort_direction = criteria.sort_direction.lower() + if crit_sort_direction == "desc" or crit_sort_direction == "descending": + query = query.order_by_descending(lambda x: getattr(x, criteria.sort_column)) + else: + query = query.order_by(lambda x: getattr(x, criteria.sort_column)) + + result = FilteredResult() + result.total_count = query.count() + skip = criteria.page_size * criteria.page_index + result.result = query.skip(skip).take(criteria.page_size) + + return result + def get_server_by_id(self, server_id: int) -> Server: self._logger.trace(__name__, f'Send SQL command: {Server.get_select_by_id_string(server_id)}') result = self._context.select(Server.get_select_by_id_string(server_id))[0] From 1baa8cee60036e4e15cc2e103db62fc273c9259e Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Mon, 17 Oct 2022 16:50:09 +0200 Subject: [PATCH 038/102] Added logic to get servers to dashboard #72 --- .../controller/discord/server_controller.py | 20 ++-- .../src/bot_api/service/discord_service.py | 45 +++++---- kdb-web/src/app/models/discord/server.dto.ts | 6 ++ .../logins/login-select-criterion.dto.ts | 8 -- .../server/get-filtered-servers-result.dto.ts | 7 ++ .../server/server-select-criterion.dto.ts | 5 + .../auth-user/auth-user.component.ts | 2 +- .../dashboard/dashboard.component.html | 15 ++- .../dashboard/dashboard.component.ts | 95 ++++++++++++++++++- kdb-web/src/app/services/data/data.service.ts | 33 ++++++- kdb-web/src/assets/i18n/de.json | 4 +- 11 files changed, 191 insertions(+), 49 deletions(-) create mode 100644 kdb-web/src/app/models/discord/server.dto.ts delete mode 100644 kdb-web/src/app/models/selection/logins/login-select-criterion.dto.ts create mode 100644 kdb-web/src/app/models/selection/server/get-filtered-servers-result.dto.ts create mode 100644 kdb-web/src/app/models/selection/server/server-select-criterion.dto.ts diff --git a/kdb-bot/src/bot_api/controller/discord/server_controller.py b/kdb-bot/src/bot_api/controller/discord/server_controller.py index 35a3fa9c96..d2c89b1049 100644 --- a/kdb-bot/src/bot_api/controller/discord/server_controller.py +++ b/kdb-bot/src/bot_api/controller/discord/server_controller.py @@ -36,24 +36,24 @@ class ServerController: self._mailer = mailer self._discord_service = discord_service - @Route.get(f'{BasePath}/servers') + @Route.get(f'{BasePath}/get/servers') @Route.authorize(role=AuthRoleEnum.admin) async def get_all_servers(self) -> Response: result = await self._discord_service.get_all_servers() result = result.select(lambda x: x.to_dict()) return jsonify(result) - @Route.get(f'{BasePath}/servers/get/filtered') - @Route.authorize - async def get_all_servers_by_user(self) -> Response: - dto: ServerSelectCriteria = JSONProcessor.process(ServerSelectCriteria, request.get_json(force=True, silent=True)) - result = await self._discord_service.get_filtered_servers_async(dto) - result.result = result.result.select(lambda x: x.to_dict()) - return jsonify(result.to_dict()) - - @Route.get(f'{BasePath}/servers-by-user') + @Route.get(f'{BasePath}/get/servers-by-user') @Route.authorize async def get_all_servers_by_user(self) -> Response: result = await self._discord_service.get_all_servers_by_user() result = result.select(lambda x: x.to_dict()) return jsonify(result) + + @Route.post(f'{BasePath}/get/filtered') + @Route.authorize + async def get_filtered_servers(self) -> Response: + dto: ServerSelectCriteria = JSONProcessor.process(ServerSelectCriteria, request.get_json(force=True, silent=True)) + result = await self._discord_service.get_filtered_servers_async(dto) + result.result = result.result.select(lambda x: x.to_dict()) + return jsonify(result.to_dict()) diff --git a/kdb-bot/src/bot_api/service/discord_service.py b/kdb-bot/src/bot_api/service/discord_service.py index e00e5b8486..6f8e5f13bb 100644 --- a/kdb-bot/src/bot_api/service/discord_service.py +++ b/kdb-bot/src/bot_api/service/discord_service.py @@ -37,29 +37,6 @@ class DiscordService: lambda x: ServerTransformer.to_dto(x, self._bot.get_guild(x.discord_server_id).name, self._bot.get_guild(x.discord_server_id).member_count) ) - async def get_filtered_servers_async(self, criteria: ServerSelectCriteria) -> ServerFilteredResultDTO: - token = self._auth.get_decoded_token_from_request() - if token is None or 'email' not in token or 'role' not in token: - raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid') - - role = AuthRoleEnum(token['role']) - role = AuthRoleEnum(token['role']) - filtered_result = self._servers.get_filtered_servers(criteria) - servers = filtered_result.result - if role != AuthRoleEnum.admin: - user = await self._auth.find_auth_user_by_email_async(token['email']) - user_from_db = self._users.find_user_by_id(0 if user.user_id is None else user.user_id) - servers = servers.where(lambda x: user_from_db is not None and x.server_id == user_from_db.server.server_id) - - result = servers.select( - lambda x: ServerTransformer.to_dto(x, self._bot.get_guild(x.discord_server_id).name, self._bot.get_guild(x.discord_server_id).member_count) - ) - - return ServerFilteredResultDTO( - List(ServerDTO, result), - servers.total_count - ) - async def get_all_servers_by_user(self) -> List[ServerDTO]: token = self._auth.get_decoded_token_from_request() if token is None or 'email' not in token or 'role' not in token: @@ -76,3 +53,25 @@ class DiscordService: return servers.select( lambda x: ServerTransformer.to_dto(x, self._bot.get_guild(x.discord_server_id).name, self._bot.get_guild(x.discord_server_id).member_count) ) + + async def get_filtered_servers_async(self, criteria: ServerSelectCriteria) -> ServerFilteredResultDTO: + token = self._auth.get_decoded_token_from_request() + if token is None or 'email' not in token or 'role' not in token: + raise ServiceException(ServiceErrorCode.InvalidData, 'Token invalid') + + role = AuthRoleEnum(token['role']) + filtered_result = self._servers.get_filtered_servers(criteria) + servers = filtered_result.result + if role != AuthRoleEnum.admin: + user = await self._auth.find_auth_user_by_email_async(token['email']) + user_from_db = self._users.find_user_by_id(0 if user.user_id is None else user.user_id) + servers = servers.where(lambda x: user_from_db is not None and x.server_id == user_from_db.server.server_id) + + result = servers.select( + lambda x: ServerTransformer.to_dto(x, self._bot.get_guild(x.discord_server_id).name, self._bot.get_guild(x.discord_server_id).member_count) + ) + + return ServerFilteredResultDTO( + List(ServerDTO, result), + filtered_result.total_count + ) diff --git a/kdb-web/src/app/models/discord/server.dto.ts b/kdb-web/src/app/models/discord/server.dto.ts new file mode 100644 index 0000000000..4cba26ac6a --- /dev/null +++ b/kdb-web/src/app/models/discord/server.dto.ts @@ -0,0 +1,6 @@ +export interface ServerDTO { + serverId: number; + discordId: number; + name: string; + memberCount: number; +} \ No newline at end of file diff --git a/kdb-web/src/app/models/selection/logins/login-select-criterion.dto.ts b/kdb-web/src/app/models/selection/logins/login-select-criterion.dto.ts deleted file mode 100644 index e1998d60bc..0000000000 --- a/kdb-web/src/app/models/selection/logins/login-select-criterion.dto.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { SelectCriterion } from "../select-criterion.model"; - -export interface LoginSelectCriterion extends SelectCriterion { - timeFrom: string; - timeTo: string; - userName: string; - hostName: string; -} \ No newline at end of file diff --git a/kdb-web/src/app/models/selection/server/get-filtered-servers-result.dto.ts b/kdb-web/src/app/models/selection/server/get-filtered-servers-result.dto.ts new file mode 100644 index 0000000000..4dfe801a2b --- /dev/null +++ b/kdb-web/src/app/models/selection/server/get-filtered-servers-result.dto.ts @@ -0,0 +1,7 @@ +import { AuthUserDTO } from "../../auth/auth-user.dto"; +import { ServerDTO } from "../../discord/server.dto"; + +export interface GetFilteredServersResultDTO { + servers: ServerDTO[]; + totalCount: number; +} \ No newline at end of file diff --git a/kdb-web/src/app/models/selection/server/server-select-criterion.dto.ts b/kdb-web/src/app/models/selection/server/server-select-criterion.dto.ts new file mode 100644 index 0000000000..08b9ea5925 --- /dev/null +++ b/kdb-web/src/app/models/selection/server/server-select-criterion.dto.ts @@ -0,0 +1,5 @@ +import { SelectCriterion } from "../select-criterion.model"; + +export interface ServerSelectCriterion extends SelectCriterion { + name: string | null; +} \ No newline at end of file diff --git a/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts b/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts index c972e7f215..a9243563b6 100644 --- a/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts +++ b/kdb-web/src/app/modules/admin/auth-users/components/auth-user/auth-user.component.ts @@ -85,7 +85,7 @@ export class AuthUserComponent implements OnInit { }; this.setFilterForm(); - // this.loadNextPage(); + this.loadNextPage(); } setFilterForm() { diff --git a/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.html b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.html index 04e795ec56..e4139bace0 100644 --- a/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.html +++ b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.html @@ -1,3 +1,12 @@ -

dashboard works!

- -
+

+ {{'view.dashboard.header' | translate}} +

+
+
+
    +
  • + {{server.name}} +
  • +
+
+
\ No newline at end of file diff --git a/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts index 25d48a7ae5..0fb3ff19a4 100644 --- a/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts +++ b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts @@ -1,4 +1,14 @@ import { Component, OnInit } from '@angular/core'; +import { FormGroup, FormControl, FormBuilder } from '@angular/forms'; +import { TranslateService } from '@ngx-translate/core'; +import { LazyLoadEvent } from 'primeng/api'; +import { catchError, debounceTime, throwError } from 'rxjs'; +import { ServerDTO } from 'src/app/models/discord/server.dto'; +import { ServerSelectCriterion } from 'src/app/models/selection/server/server-select-criterion.dto'; +import { ConfirmationDialogService } from 'src/app/services/confirmation-dialog/confirmation-dialog.service'; +import { DataService } from 'src/app/services/data/data.service'; +import { SpinnerService } from 'src/app/services/spinner/spinner.service'; +import { ToastService } from 'src/app/services/toast/toast.service'; @Component({ selector: 'app-dashboard', @@ -7,8 +17,89 @@ import { Component, OnInit } from '@angular/core'; }) export class DashboardComponent implements OnInit { - constructor() { } + loading = true; + servers: ServerDTO[] = []; - ngOnInit(): void {} + searchCriterions: ServerSelectCriterion = { + name: null, + pageIndex: 0, + pageSize: 10, + sortColumn: null, + sortDirection: null + }; + totalRecords!: number; + + + filterForm!: FormGroup<{ + name: FormControl, + }>; + + constructor( + private data: DataService, + private spinnerService: SpinnerService, + private toastService: ToastService, + private confirmDialog: ConfirmationDialogService, + private fb: FormBuilder, + private translate: TranslateService + ) { } + + ngOnInit(): void { + this.setFilterForm(); + this.loadNextPage(); + } + + setFilterForm() { + this.filterForm = this.fb.group({ + name: [''], + }); + + this.filterForm.valueChanges.pipe( + debounceTime(600) + ).subscribe(changes => { + if (changes.name) { + this.searchCriterions.name = changes.name; + } else { + this.searchCriterions.name = null; + } + + if (this.searchCriterions.pageSize) + this.searchCriterions.pageSize = 10; + + if (this.searchCriterions.pageSize) + this.searchCriterions.pageIndex = 0; + + this.loadNextPage(); + }); + } + + loadNextPage() { + this.data.getFilteredServers(this.searchCriterions).pipe(catchError(err => { + this.loading = false; + return throwError(() => err); + })).subscribe(list => { + this.totalRecords = list.totalCount; + this.servers = list.servers; + this.loading = false; + }); + } + + nextPage(event: LazyLoadEvent) { + this.searchCriterions.pageSize = event.rows ?? 0; + if (event.first != null && event.rows != null) + this.searchCriterions.pageIndex = event.first / event.rows; + this.searchCriterions.sortColumn = event.sortField ?? null; + this.searchCriterions.sortDirection = event.sortOrder === 1 ? 'asc' : event.sortOrder === -1 ? 'desc' : 'asc'; + + if (event.filters) { + // + "" => convert to string + this.searchCriterions.name = event.filters['name'] ? event.filters['name'] + "" : null; + } + + this.loadNextPage(); + } + + resetFilters() { + this.filterForm.reset(); + } } diff --git a/kdb-web/src/app/services/data/data.service.ts b/kdb-web/src/app/services/data/data.service.ts index 36cccbb5a4..80a6060082 100644 --- a/kdb-web/src/app/services/data/data.service.ts +++ b/kdb-web/src/app/services/data/data.service.ts @@ -1,5 +1,9 @@ -import { HttpClient } from '@angular/common/http'; +import { HttpClient, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { ServerDTO } from 'src/app/models/discord/server.dto'; +import { GetFilteredServersResultDTO } from 'src/app/models/selection/server/get-filtered-servers-result.dto'; +import { ServerSelectCriterion } from 'src/app/models/selection/server/server-select-criterion.dto'; import { SettingsService } from '../settings/settings.service'; @Injectable({ @@ -11,4 +15,31 @@ export class DataService { private appsettings: SettingsService, private http: HttpClient, ) { } + + + + /* data requests */ + getAllServers(): Observable> { + return this.http.get>(`${this.appsettings.getApiURL()}/api/discord/server/servers`, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } + + getAllServersByUser(): Observable> { + return this.http.get>(`${this.appsettings.getApiURL()}/api/discord/server/servers-by-user`, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } + + getFilteredServers(selectCriterions: ServerSelectCriterion): Observable { + return this.http.post(`${this.appsettings.getApiURL()}/api/discord/server/get/filtered`, selectCriterions, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } } diff --git a/kdb-web/src/assets/i18n/de.json b/kdb-web/src/assets/i18n/de.json index 894bd46195..ae0a0f4cf9 100644 --- a/kdb-web/src/assets/i18n/de.json +++ b/kdb-web/src/assets/i18n/de.json @@ -106,7 +106,9 @@ } }, "view": { - "dashboard": {}, + "dashboard": { + "header": "Dashboard" + }, "user-list": {}, "change-password": { "header": "Passwort ändern", From a69c223a332b503134f542abd76e51b7b94c4c3c Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Mon, 17 Oct 2022 18:12:43 +0200 Subject: [PATCH 039/102] Added server list to dashboard #72 --- .../src/bot_api/model/discord/server_dto.py | 13 +++- .../src/bot_api/service/discord_service.py | 28 ++++++-- .../bot_api/transformer/server_transformer.py | 7 +- .../service/server_repository_service.py | 3 - kdb-web/src/app/models/discord/server.dto.ts | 1 + .../dashboard/dashboard.component.html | 48 +++++++++++-- kdb-web/src/assets/i18n/de.json | 11 ++- kdb-web/src/styles.scss | 67 +++++++++++++++++-- .../src/styles/themes/default-dark-theme.scss | 2 +- .../styles/themes/sh-edraft-dark-theme.scss | 43 +++++++++--- 10 files changed, 190 insertions(+), 33 deletions(-) diff --git a/kdb-bot/src/bot_api/model/discord/server_dto.py b/kdb-bot/src/bot_api/model/discord/server_dto.py index e7115dd231..07cd4365c4 100644 --- a/kdb-bot/src/bot_api/model/discord/server_dto.py +++ b/kdb-bot/src/bot_api/model/discord/server_dto.py @@ -1,3 +1,5 @@ +from typing import Optional + from bot_api.abc.dto_abc import DtoABC @@ -8,7 +10,8 @@ class ServerDTO(DtoABC): server_id: int, discord_id: int, name: str, - member_count: int + member_count: int, + icon_url: Optional[str] ): DtoABC.__init__(self) @@ -17,6 +20,7 @@ class ServerDTO(DtoABC): self._discord_id = discord_id self._name = name self._member_count = member_count + self._icon_url = icon_url @property def server_id(self) -> int: @@ -34,11 +38,15 @@ class ServerDTO(DtoABC): def member_count(self) -> int: return self._member_count + @property + def icon_url(self) -> Optional[str]: + return self._icon_url + def from_dict(self, values: dict): self._server_id = int(values['serverId']) self._discord_id = int(values['discordId']) self._name = values['name'] - self._member_count = int(values['memberCount']) + self._icon_url = int(values['iconURL']) def to_dict(self) -> dict: return { @@ -46,4 +54,5 @@ class ServerDTO(DtoABC): 'discordId': self._discord_id, 'name': self._name, 'memberCount': self._member_count, + 'iconURL': self._icon_url, } diff --git a/kdb-bot/src/bot_api/service/discord_service.py b/kdb-bot/src/bot_api/service/discord_service.py index 6f8e5f13bb..a0163dcc9e 100644 --- a/kdb-bot/src/bot_api/service/discord_service.py +++ b/kdb-bot/src/bot_api/service/discord_service.py @@ -33,9 +33,12 @@ class DiscordService: async def get_all_servers(self) -> List[ServerDTO]: servers = self._servers.get_servers() - return servers.select( - lambda x: ServerTransformer.to_dto(x, self._bot.get_guild(x.discord_server_id).name, self._bot.get_guild(x.discord_server_id).member_count) - ) + return servers.select(lambda x: ServerTransformer.to_dto( + x, + self._bot.get_guild(x.discord_server_id).name, + self._bot.get_guild(x.discord_server_id).member_count, + self._bot.get_guild(x.discord_server_id).icon + )) async def get_all_servers_by_user(self) -> List[ServerDTO]: token = self._auth.get_decoded_token_from_request() @@ -50,9 +53,12 @@ class DiscordService: user_from_db = self._users.find_user_by_id(0 if user.user_id is None else user.user_id) servers = self._servers.get_servers().where(lambda x: user_from_db is not None and x.server_id == user_from_db.server.server_id) - return servers.select( - lambda x: ServerTransformer.to_dto(x, self._bot.get_guild(x.discord_server_id).name, self._bot.get_guild(x.discord_server_id).member_count) - ) + return servers.select(lambda x: ServerTransformer.to_dto( + x, + self._bot.get_guild(x.discord_server_id).name, + self._bot.get_guild(x.discord_server_id).member_count, + self._bot.get_guild(x.discord_server_id).icon + )) async def get_filtered_servers_async(self, criteria: ServerSelectCriteria) -> ServerFilteredResultDTO: token = self._auth.get_decoded_token_from_request() @@ -68,9 +74,17 @@ class DiscordService: servers = servers.where(lambda x: user_from_db is not None and x.server_id == user_from_db.server.server_id) result = servers.select( - lambda x: ServerTransformer.to_dto(x, self._bot.get_guild(x.discord_server_id).name, self._bot.get_guild(x.discord_server_id).member_count) + lambda x: ServerTransformer.to_dto( + x, + self._bot.get_guild(x.discord_server_id).name, + self._bot.get_guild(x.discord_server_id).member_count, + self._bot.get_guild(x.discord_server_id).icon + ) ) + if criteria.name is not None and criteria.name != '': + result = result.where(lambda x: criteria.name.lower() in x.name.lower() or x.name.lower() == criteria.name.lower()) + return ServerFilteredResultDTO( List(ServerDTO, result), filtered_result.total_count diff --git a/kdb-bot/src/bot_api/transformer/server_transformer.py b/kdb-bot/src/bot_api/transformer/server_transformer.py index 920fd506d0..d883c42d5d 100644 --- a/kdb-bot/src/bot_api/transformer/server_transformer.py +++ b/kdb-bot/src/bot_api/transformer/server_transformer.py @@ -1,3 +1,7 @@ +from typing import Optional + +import discord + from bot_api.abc.transformer_abc import TransformerABC from bot_api.model.discord.server_dto import ServerDTO from bot_data.model.server import Server @@ -10,10 +14,11 @@ class ServerTransformer(TransformerABC): return Server(dto.discord_id) @staticmethod - def to_dto(db: Server, name: str, member_count: int) -> ServerDTO: + def to_dto(db: Server, name: str, member_count: int, icon_url: Optional[discord.Asset]) -> ServerDTO: return ServerDTO( db.server_id, db.discord_server_id, name, member_count, + icon_url.url if icon_url is not None else None, ) diff --git a/kdb-bot/src/bot_data/service/server_repository_service.py b/kdb-bot/src/bot_data/service/server_repository_service.py index 37b2918e2c..210a6dee95 100644 --- a/kdb-bot/src/bot_data/service/server_repository_service.py +++ b/kdb-bot/src/bot_data/service/server_repository_service.py @@ -35,9 +35,6 @@ class ServerRepositoryService(ServerRepositoryABC): self._logger.trace(__name__, f'Send SQL command: {Server.get_select_all_string()}') query = servers - if criteria.name is not None and criteria.name != '': - query = query.where(lambda x: criteria.name in x.first_name or x.first_name == criteria.name) - # sort if criteria.sort_column is not None and criteria.sort_column != '' and criteria.sort_direction is not None and criteria.sort_direction: crit_sort_direction = criteria.sort_direction.lower() diff --git a/kdb-web/src/app/models/discord/server.dto.ts b/kdb-web/src/app/models/discord/server.dto.ts index 4cba26ac6a..a97625b50a 100644 --- a/kdb-web/src/app/models/discord/server.dto.ts +++ b/kdb-web/src/app/models/discord/server.dto.ts @@ -3,4 +3,5 @@ export interface ServerDTO { discordId: number; name: string; memberCount: number; + iconURL: string | null; } \ No newline at end of file diff --git a/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.html b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.html index e4139bace0..c7dd5fdfbe 100644 --- a/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.html +++ b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.html @@ -2,11 +2,49 @@ {{'view.dashboard.header' | translate}}
+
+

+ + {{'view.dashboard.server.header' | translate}} +

+
+
-
    -
  • - {{server.name}} -
  • -
+
+
+
+
+ +
+
+
+ +
+ {{servers.length}} {{'view.dashboard.of' | translate}} {{totalRecords}} {{'view.dashboard.servers' | translate}}: +
+
+ +
+
+ + +
+

+ {{server.name}} +

+ +
+ + {{server.memberCount}} + {{'view.dashboard.server.member_count' | translate}} +
+
+ +
+
+
\ No newline at end of file diff --git a/kdb-web/src/assets/i18n/de.json b/kdb-web/src/assets/i18n/de.json index ae0a0f4cf9..83fd1ae359 100644 --- a/kdb-web/src/assets/i18n/de.json +++ b/kdb-web/src/assets/i18n/de.json @@ -107,7 +107,16 @@ }, "view": { "dashboard": { - "header": "Dashboard" + "header": "Dashboard", + "of": "von", + "servers": "Server", + "server": { + "header": "Server", + "member_count": "Mitglid(er)" + }, + "filter": { + "name": "Name" + } }, "user-list": {}, "change-password": { diff --git a/kdb-web/src/styles.scss b/kdb-web/src/styles.scss index ee146861c3..8bbd6cd8a5 100644 --- a/kdb-web/src/styles.scss +++ b/kdb-web/src/styles.scss @@ -10,6 +10,8 @@ body { height: 100%; padding: 0; margin: 0; + + font-size: 1rem; } main { @@ -18,15 +20,19 @@ main { min-height: 100vh; } -h1, -h2 { +h1 { margin: 0; - font-size: 30px; + font-size: 1.75rem; } h2 { margin: 0; - font-size: 25px; + font-size: 1.5rem; +} + +h3 { + margin: 0; + font-size: 1.25rem; } header { @@ -207,6 +213,59 @@ header { .table-header-small-dropdown { width: 150px; } + + .server-list-wrapper { + display: flex; + flex-direction: column; + gap: 10px; + + .server-filter { + } + + .server-count { + } + + .server-list { + display: flex; + flex-direction: column; + + gap: 15px; + + .server { + display: flex; + gap: 15px; + + padding: 20px; + + .logo { + overflow: hidden; + + img { + width: 4rem; + height: 4rem; + object-fit: contain; + } + } + + .info { + display: flex; + flex-direction: column; + + gap: 10px; + + .name { + margin: 0px; + + justify-content: center; + align-items: center; + } + + .data { + } + } + } + } + } } } } diff --git a/kdb-web/src/styles/themes/default-dark-theme.scss b/kdb-web/src/styles/themes/default-dark-theme.scss index 7507a6cb05..1a3bd5d178 100644 --- a/kdb-web/src/styles/themes/default-dark-theme.scss +++ b/kdb-web/src/styles/themes/default-dark-theme.scss @@ -432,7 +432,7 @@ color: $primaryTextColor !important; border: 0 !important; padding: 0px !important; - + &:hover { background-color: transparent !important; color: $primaryHeaderColor !important; diff --git a/kdb-web/src/styles/themes/sh-edraft-dark-theme.scss b/kdb-web/src/styles/themes/sh-edraft-dark-theme.scss index ee2da9f469..8fa192f1f0 100644 --- a/kdb-web/src/styles/themes/sh-edraft-dark-theme.scss +++ b/kdb-web/src/styles/themes/sh-edraft-dark-theme.scss @@ -15,17 +15,10 @@ $primaryErrorColor: #b00020; $secondaryErrorColor: #e94948; - $default-border: 1px solid $secondaryBackgroundColor3; + $default-border: 2px solid $secondaryBackgroundColor3; background-color: $primaryBackgroundColor !important; - html, - body { - margin: 0; - - font-size: 16px; - } - h1, h2 { color: $primaryHeaderColor; @@ -122,6 +115,35 @@ .content-divider { border-bottom: $default-border; } + + .server-list-wrapper { + .server-filter { + } + + .server-count { + } + + .server-list { + .server { + border: $default-border; + border-radius: 15px; + + .logo { + img { + border-radius: 100%; + } + } + + .name { + color: $primaryHeaderColor; + } + + &:hover { + border-color: $primaryHeaderColor !important; + } + } + } + } } } } @@ -390,6 +412,9 @@ input, .p-password { + border-radius: 10px; + border: $default-border; + &:focus { box-shadow: none !important; } @@ -434,7 +459,7 @@ color: $primaryTextColor !important; border: 0 !important; padding: 0px !important; - + &:hover { background-color: transparent !important; color: $primaryHeaderColor !important; From 2a974384172e127f835afc1daa2ac013c0297c02 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Mon, 17 Oct 2022 19:44:28 +0200 Subject: [PATCH 040/102] [WIP] Added server dashboard #72 --- .../controller/discord/server_controller.py | 6 +++ .../src/bot_api/service/discord_service.py | 7 +++ kdb-web/src/app/app-routing.module.ts | 1 + .../dashboard/dashboard.component.html | 2 +- .../dashboard/dashboard.component.ts | 17 ++++--- .../dashboard/dashboard-routing.module.ts | 2 +- .../view/dashboard/dashboard.module.ts | 6 +-- .../server-dashboard.component.html | 36 +++++++++++++++ .../server-dashboard.component.scss | 0 .../server-dashboard.component.spec.ts | 23 ++++++++++ .../server-dashboard.component.ts | 45 +++++++++++++++++++ .../view/server/server-routing.module.ts | 14 ++++++ .../app/modules/view/server/server.module.ts | 19 ++++++++ kdb-web/src/app/services/data/data.service.ts | 8 ++++ kdb-web/src/assets/i18n/de.json | 9 ++-- 15 files changed, 181 insertions(+), 14 deletions(-) create mode 100644 kdb-web/src/app/modules/view/server/server-dashboard/server-dashboard.component.html create mode 100644 kdb-web/src/app/modules/view/server/server-dashboard/server-dashboard.component.scss create mode 100644 kdb-web/src/app/modules/view/server/server-dashboard/server-dashboard.component.spec.ts create mode 100644 kdb-web/src/app/modules/view/server/server-dashboard/server-dashboard.component.ts create mode 100644 kdb-web/src/app/modules/view/server/server-routing.module.ts create mode 100644 kdb-web/src/app/modules/view/server/server.module.ts diff --git a/kdb-bot/src/bot_api/controller/discord/server_controller.py b/kdb-bot/src/bot_api/controller/discord/server_controller.py index d2c89b1049..1c362ab957 100644 --- a/kdb-bot/src/bot_api/controller/discord/server_controller.py +++ b/kdb-bot/src/bot_api/controller/discord/server_controller.py @@ -57,3 +57,9 @@ class ServerController: result = await self._discord_service.get_filtered_servers_async(dto) result.result = result.result.select(lambda x: x.to_dict()) return jsonify(result.to_dict()) + + @Route.get(f'{BasePath}/get/') + @Route.authorize + async def get_server_by_id(self, id: int) -> Response: + result = await self._discord_service.get_server_by_id_async(id) + return jsonify(result.to_dict()) diff --git a/kdb-bot/src/bot_api/service/discord_service.py b/kdb-bot/src/bot_api/service/discord_service.py index a0163dcc9e..7266e1bd4a 100644 --- a/kdb-bot/src/bot_api/service/discord_service.py +++ b/kdb-bot/src/bot_api/service/discord_service.py @@ -89,3 +89,10 @@ class DiscordService: List(ServerDTO, result), filtered_result.total_count ) + + async def get_server_by_id_async(self, id: int) -> ServerDTO: + server = self._servers.get_server_by_id(id) + guild = self._bot.get_guild(server.discord_server_id) + + server_dto = ServerTransformer.to_dto(server, guild.name, guild.member_count, guild.icon) + return server_dto diff --git a/kdb-web/src/app/app-routing.module.ts b/kdb-web/src/app/app-routing.module.ts index 803deb705b..1a1c9c3b46 100644 --- a/kdb-web/src/app/app-routing.module.ts +++ b/kdb-web/src/app/app-routing.module.ts @@ -7,6 +7,7 @@ import { AuthGuard } from './modules/shared/guards/auth/auth.guard'; const routes: Routes = [ { path: '', redirectTo: 'dashboard', pathMatch: 'full' }, { path: 'dashboard', loadChildren: () => import('./modules/view/dashboard/dashboard.module').then(m => m.DashboardModule), canActivate: [AuthGuard] }, + { path: 'server', loadChildren: () => import('./modules/view/server/server.module').then(m => m.ServerModule), canActivate: [AuthGuard] }, { path: 'change-password', loadChildren: () => import('./modules/view/change-password/change-password.module').then(m => m.ChangePasswordModule), canActivate: [AuthGuard] }, { path: 'user-settings', loadChildren: () => import('./modules/view/user-settings/user-settings.module').then(m => m.UserSettingsModule), canActivate: [AuthGuard] }, { path: 'auth', loadChildren: () => import('./modules/auth/auth.module').then(m => m.AuthModule) }, diff --git a/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.html b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.html index c7dd5fdfbe..ded533101a 100644 --- a/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.html +++ b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.html @@ -26,7 +26,7 @@
-
+
diff --git a/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts index 0fb3ff19a4..d149298e49 100644 --- a/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts +++ b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts @@ -1,5 +1,6 @@ import { Component, OnInit } from '@angular/core'; -import { FormGroup, FormControl, FormBuilder } from '@angular/forms'; +import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; +import { Router } from '@angular/router'; import { TranslateService } from '@ngx-translate/core'; import { LazyLoadEvent } from 'primeng/api'; import { catchError, debounceTime, throwError } from 'rxjs'; @@ -17,7 +18,6 @@ import { ToastService } from 'src/app/services/toast/toast.service'; }) export class DashboardComponent implements OnInit { - loading = true; servers: ServerDTO[] = []; searchCriterions: ServerSelectCriterion = { @@ -40,10 +40,12 @@ export class DashboardComponent implements OnInit { private toastService: ToastService, private confirmDialog: ConfirmationDialogService, private fb: FormBuilder, - private translate: TranslateService + private translate: TranslateService, + private router: Router ) { } ngOnInit(): void { + this.spinnerService.showSpinner(); this.setFilterForm(); this.loadNextPage(); } @@ -73,13 +75,14 @@ export class DashboardComponent implements OnInit { } loadNextPage() { + this.spinnerService.showSpinner(); this.data.getFilteredServers(this.searchCriterions).pipe(catchError(err => { - this.loading = false; + this.spinnerService.hideSpinner(); return throwError(() => err); })).subscribe(list => { this.totalRecords = list.totalCount; this.servers = list.servers; - this.loading = false; + this.spinnerService.hideSpinner(); }); } @@ -102,4 +105,8 @@ export class DashboardComponent implements OnInit { this.filterForm.reset(); } + selectServer(server: ServerDTO) { + this.router.navigate(['/server', server.serverId]); + } + } diff --git a/kdb-web/src/app/modules/view/dashboard/dashboard-routing.module.ts b/kdb-web/src/app/modules/view/dashboard/dashboard-routing.module.ts index 27f772462c..37add74128 100644 --- a/kdb-web/src/app/modules/view/dashboard/dashboard-routing.module.ts +++ b/kdb-web/src/app/modules/view/dashboard/dashboard-routing.module.ts @@ -3,7 +3,7 @@ import { RouterModule, Routes } from '@angular/router'; import { DashboardComponent } from './components/dashboard/dashboard.component'; const routes: Routes = [ - {path: '', component: DashboardComponent} + { path: '', component: DashboardComponent } ]; @NgModule({ diff --git a/kdb-web/src/app/modules/view/dashboard/dashboard.module.ts b/kdb-web/src/app/modules/view/dashboard/dashboard.module.ts index 0b3abe11d6..80438b6ee9 100644 --- a/kdb-web/src/app/modules/view/dashboard/dashboard.module.ts +++ b/kdb-web/src/app/modules/view/dashboard/dashboard.module.ts @@ -1,9 +1,9 @@ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; -import { DashboardRoutingModule } from './dashboard-routing.module'; -import { DashboardComponent } from './components/dashboard/dashboard.component'; import { SharedModule } from '../../shared/shared.module'; +import { DashboardComponent } from './components/dashboard/dashboard.component'; +import { DashboardRoutingModule } from './dashboard-routing.module'; @NgModule({ diff --git a/kdb-web/src/app/modules/view/server/server-dashboard/server-dashboard.component.html b/kdb-web/src/app/modules/view/server/server-dashboard/server-dashboard.component.html new file mode 100644 index 0000000000..1fbf61d3c5 --- /dev/null +++ b/kdb-web/src/app/modules/view/server/server-dashboard/server-dashboard.component.html @@ -0,0 +1,36 @@ +

+ {{'view.dashboard.header' | translate}} +

+
+
+

+ + {{'view.dashboard.server.header' | translate}} +

+
+ +
+
+
+
+ + +
+

+ {{server.name}} +

+ +
+ + {{server.memberCount}} + {{'view.dashboard.server.member_count' | translate}} +
+
+ +
+
+
+
+
\ No newline at end of file diff --git a/kdb-web/src/app/modules/view/server/server-dashboard/server-dashboard.component.scss b/kdb-web/src/app/modules/view/server/server-dashboard/server-dashboard.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-web/src/app/modules/view/server/server-dashboard/server-dashboard.component.spec.ts b/kdb-web/src/app/modules/view/server/server-dashboard/server-dashboard.component.spec.ts new file mode 100644 index 0000000000..9f49b43a16 --- /dev/null +++ b/kdb-web/src/app/modules/view/server/server-dashboard/server-dashboard.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ServerDashboardComponent } from './server-dashboard.component'; + +describe('ServerDashboardComponent', () => { + let component: ServerDashboardComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ ServerDashboardComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ServerDashboardComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/modules/view/server/server-dashboard/server-dashboard.component.ts b/kdb-web/src/app/modules/view/server/server-dashboard/server-dashboard.component.ts new file mode 100644 index 0000000000..540ac8b639 --- /dev/null +++ b/kdb-web/src/app/modules/view/server/server-dashboard/server-dashboard.component.ts @@ -0,0 +1,45 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { catchError, throwError } from 'rxjs'; +import { ServerDTO } from 'src/app/models/discord/server.dto'; +import { DataService } from 'src/app/services/data/data.service'; +import { SpinnerService } from 'src/app/services/spinner/spinner.service'; + +@Component({ + selector: 'app-server-dashboard', + templateUrl: './server-dashboard.component.html', + styleUrls: ['./server-dashboard.component.scss'] +}) +export class ServerDashboardComponent implements OnInit { + + id!: number; + server!: ServerDTO; + + constructor( + private route: ActivatedRoute, + private router: Router, + private data: DataService, + private spinner: SpinnerService + ) { } + + ngOnInit(): void { + this.route.params.subscribe(params => { + this.id = +params['id']; + + if (!this.id) { + this.router.navigate(['/dashboard']); + return; + } + + this.spinner.showSpinner(); + this.data.getServerByID(this.id).pipe(catchError(err => { + this.spinner.hideSpinner(); + return throwError(() => err); + })).subscribe(server => { + this.server = server; + this.spinner.hideSpinner(); + }); + }); + } + +} diff --git a/kdb-web/src/app/modules/view/server/server-routing.module.ts b/kdb-web/src/app/modules/view/server/server-routing.module.ts new file mode 100644 index 0000000000..063beab12c --- /dev/null +++ b/kdb-web/src/app/modules/view/server/server-routing.module.ts @@ -0,0 +1,14 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { ServerDashboardComponent } from './server-dashboard/server-dashboard.component'; + +const routes: Routes = [ + { path: '', component: ServerDashboardComponent }, + { path: ':id', component: ServerDashboardComponent } +]; + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class ServerRoutingModule { } diff --git a/kdb-web/src/app/modules/view/server/server.module.ts b/kdb-web/src/app/modules/view/server/server.module.ts new file mode 100644 index 0000000000..824e2412df --- /dev/null +++ b/kdb-web/src/app/modules/view/server/server.module.ts @@ -0,0 +1,19 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ServerDashboardComponent } from './server-dashboard/server-dashboard.component'; +import { ServerRoutingModule } from './server-routing.module'; +import { SharedModule } from '../../shared/shared.module'; + + + +@NgModule({ + declarations: [ + ServerDashboardComponent + ], + imports: [ + CommonModule, + ServerRoutingModule, + SharedModule + ] +}) +export class ServerModule { } diff --git a/kdb-web/src/app/services/data/data.service.ts b/kdb-web/src/app/services/data/data.service.ts index 80a6060082..6b1a0f76a7 100644 --- a/kdb-web/src/app/services/data/data.service.ts +++ b/kdb-web/src/app/services/data/data.service.ts @@ -42,4 +42,12 @@ export class DataService { }) }); } + + getServerByID(id: number): Observable { + return this.http.get(`${this.appsettings.getApiURL()}/api/discord/server/get/${id}`, { + headers: new HttpHeaders({ + 'Content-Type': 'application/json' + }) + }); + } } diff --git a/kdb-web/src/assets/i18n/de.json b/kdb-web/src/assets/i18n/de.json index 83fd1ae359..96fa7213ee 100644 --- a/kdb-web/src/assets/i18n/de.json +++ b/kdb-web/src/assets/i18n/de.json @@ -7,10 +7,8 @@ }, "sidebar": { "dashboard": "Dashboard", - "domain_list": "Domänen", - "host_list": "Rechner", - "user_list": "Benutzer", - "login_list": "Logins", + "server": "Server", + "server_empty": "Kein Server ausgewählt", "config": "Konfiguration", "auth_user_list": "Benutzer" }, @@ -118,6 +116,9 @@ "name": "Name" } }, + "server": { + "header": "Server" + }, "user-list": {}, "change-password": { "header": "Passwort ändern", From c094a3efae3a05ff82e4fdd45cac4d7db5a356ff Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Tue, 18 Oct 2022 12:41:42 +0200 Subject: [PATCH 041/102] Improved get server logic #72 --- .../src/bot_api/service/discord_service.py | 51 ++++++++++--------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/kdb-bot/src/bot_api/service/discord_service.py b/kdb-bot/src/bot_api/service/discord_service.py index 7266e1bd4a..304e340a95 100644 --- a/kdb-bot/src/bot_api/service/discord_service.py +++ b/kdb-bot/src/bot_api/service/discord_service.py @@ -15,6 +15,7 @@ from bot_api.transformer.server_transformer import ServerTransformer from bot_data.abc.server_repository_abc import ServerRepositoryABC from bot_data.abc.user_repository_abc import UserRepositoryABC from bot_data.model.auth_role_enum import AuthRoleEnum +from bot_data.model.server import Server class DiscordService: @@ -31,14 +32,26 @@ class DiscordService: self._auth = auth self._users = users + def _to_dto(self, x: Server) -> Optional[ServerDTO]: + guild = self._bot.get_guild(x.discord_server_id) + if guild is None: + return ServerTransformer.to_dto( + x, + '', + 0, + None + ) + + return ServerTransformer.to_dto( + x, + guild.name, + guild.member_count, + guild.icon + ) + async def get_all_servers(self) -> List[ServerDTO]: - servers = self._servers.get_servers() - return servers.select(lambda x: ServerTransformer.to_dto( - x, - self._bot.get_guild(x.discord_server_id).name, - self._bot.get_guild(x.discord_server_id).member_count, - self._bot.get_guild(x.discord_server_id).icon - )) + servers = List(ServerDTO, self._servers.get_servers()) + return servers.select(self._to_dto).where(lambda x: x.name != '') async def get_all_servers_by_user(self) -> List[ServerDTO]: token = self._auth.get_decoded_token_from_request() @@ -53,12 +66,8 @@ class DiscordService: user_from_db = self._users.find_user_by_id(0 if user.user_id is None else user.user_id) servers = self._servers.get_servers().where(lambda x: user_from_db is not None and x.server_id == user_from_db.server.server_id) - return servers.select(lambda x: ServerTransformer.to_dto( - x, - self._bot.get_guild(x.discord_server_id).name, - self._bot.get_guild(x.discord_server_id).member_count, - self._bot.get_guild(x.discord_server_id).icon - )) + servers = List(ServerDTO, servers) + return servers.select(self._to_dto).where(lambda x: x.name != '') async def get_filtered_servers_async(self, criteria: ServerSelectCriteria) -> ServerFilteredResultDTO: token = self._auth.get_decoded_token_from_request() @@ -67,27 +76,21 @@ class DiscordService: role = AuthRoleEnum(token['role']) filtered_result = self._servers.get_filtered_servers(criteria) - servers = filtered_result.result + # filter out servers, where the user not exists if role != AuthRoleEnum.admin: user = await self._auth.find_auth_user_by_email_async(token['email']) user_from_db = self._users.find_user_by_id(0 if user.user_id is None else user.user_id) - servers = servers.where(lambda x: user_from_db is not None and x.server_id == user_from_db.server.server_id) + filtered_result.result = filtered_result.result.where(lambda x: user_from_db is not None and x.server_id == user_from_db.server.server_id) - result = servers.select( - lambda x: ServerTransformer.to_dto( - x, - self._bot.get_guild(x.discord_server_id).name, - self._bot.get_guild(x.discord_server_id).member_count, - self._bot.get_guild(x.discord_server_id).icon - ) - ) + servers: List = filtered_result.result.select(self._to_dto).where(lambda x: x.name != '') + result = List(ServerDTO, servers) if criteria.name is not None and criteria.name != '': result = result.where(lambda x: criteria.name.lower() in x.name.lower() or x.name.lower() == criteria.name.lower()) return ServerFilteredResultDTO( List(ServerDTO, result), - filtered_result.total_count + servers.count() ) async def get_server_by_id_async(self, id: int) -> ServerDTO: From 1055d5c2e19f632da0916618158498c05426712f Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Tue, 18 Oct 2022 13:44:13 +0200 Subject: [PATCH 042/102] Improved design of menu to handle servers #72 --- kdb-web/.prettierrc | 4 +++ .../components/sidebar/sidebar.component.html | 2 +- .../components/sidebar/sidebar.component.ts | 16 ++++++++-- .../src/app/modules/shared/shared.module.ts | 5 ++- .../src/app/services/theme/theme.service.ts | 2 +- kdb-web/src/assets/i18n/de.json | 25 ++++----------- kdb-web/src/styles/primeng-fixes.scss | 32 +++++++++++++++++-- .../styles/themes/sh-edraft-dark-theme.scss | 25 ++++++++++++--- 8 files changed, 79 insertions(+), 32 deletions(-) create mode 100644 kdb-web/.prettierrc diff --git a/kdb-web/.prettierrc b/kdb-web/.prettierrc new file mode 100644 index 0000000000..5a938ce18e --- /dev/null +++ b/kdb-web/.prettierrc @@ -0,0 +1,4 @@ +{ + "tabWidth": 4, + "useTabs": false +} diff --git a/kdb-web/src/app/components/sidebar/sidebar.component.html b/kdb-web/src/app/components/sidebar/sidebar.component.html index b3bb4f3ba9..6f72d17e6c 100644 --- a/kdb-web/src/app/components/sidebar/sidebar.component.html +++ b/kdb-web/src/app/components/sidebar/sidebar.component.html @@ -1,3 +1,3 @@ \ No newline at end of file diff --git a/kdb-web/src/app/components/sidebar/sidebar.component.ts b/kdb-web/src/app/components/sidebar/sidebar.component.ts index cbf13c6f7c..f7815fbdcb 100644 --- a/kdb-web/src/app/components/sidebar/sidebar.component.ts +++ b/kdb-web/src/app/components/sidebar/sidebar.component.ts @@ -40,6 +40,13 @@ export class SidebarComponent implements OnInit { this.menuItems = []; this.menuItems = [ { label: this.isSidebarOpen ? this.translateService.instant('sidebar.dashboard') : '', icon: 'pi pi-th-large', routerLink: 'dashboard' }, + + { + label: this.isSidebarOpen ? this.translateService.instant('sidebar.server') : '', icon: 'pi pi-server', items: [ + { label: this.isSidebarOpen ? this.translateService.instant('sidebar.settings') : '', icon: 'pi pi-cog', routerLink: 'server/id/settings' }, + { label: this.isSidebarOpen ? this.translateService.instant('sidebar.members') : '', icon: 'pi pi-user-edit', routerLink: 'server/id/members' }, + ] + }, ]; if (!hasPermission) { @@ -47,9 +54,12 @@ export class SidebarComponent implements OnInit { } this.menuItems.push( - { separator: true }, - { label: this.isSidebarOpen ? this.translateService.instant('sidebar.config') : '', icon: 'pi pi-cog', routerLink: '/admin/settings' }, - { label: this.isSidebarOpen ? this.translateService.instant('sidebar.auth_user_list') : '', icon: 'pi pi-user-edit', routerLink: '/admin/users' }, + { + label: this.isSidebarOpen ? this.translateService.instant('sidebar.administration') : '', icon: 'pi pi-cog', items: [ + { label: this.isSidebarOpen ? this.translateService.instant('sidebar.config') : '', icon: 'pi pi-cog', routerLink: '/admin/settings' }, + { label: this.isSidebarOpen ? this.translateService.instant('sidebar.auth_user_list') : '', icon: 'pi pi-user-edit', routerLink: '/admin/users' }, + ] + }, ); this.menuItems = this.menuItems.slice(); }); diff --git a/kdb-web/src/app/modules/shared/shared.module.ts b/kdb-web/src/app/modules/shared/shared.module.ts index 9a77a513cc..59c0d0ef06 100644 --- a/kdb-web/src/app/modules/shared/shared.module.ts +++ b/kdb-web/src/app/modules/shared/shared.module.ts @@ -18,6 +18,7 @@ import { ToastModule } from 'primeng/toast'; import { AuthRolePipe } from './pipes/auth-role.pipe'; import { IpAddressPipe } from './pipes/ip-address.pipe'; import { BoolPipe } from './pipes/bool.pipe'; +import { PanelMenuModule } from 'primeng/panelmenu'; @@ -44,7 +45,8 @@ import { BoolPipe } from './pipes/bool.pipe'; CheckboxModule, DropdownModule, TranslateModule, - DynamicDialogModule + DynamicDialogModule, + PanelMenuModule, ], exports: [ ButtonModule, @@ -63,6 +65,7 @@ import { BoolPipe } from './pipes/bool.pipe'; DropdownModule, TranslateModule, DynamicDialogModule, + PanelMenuModule, AuthRolePipe, IpAddressPipe, BoolPipe, diff --git a/kdb-web/src/app/services/theme/theme.service.ts b/kdb-web/src/app/services/theme/theme.service.ts index 914ba774ef..6dc3410ab2 100644 --- a/kdb-web/src/app/services/theme/theme.service.ts +++ b/kdb-web/src/app/services/theme/theme.service.ts @@ -27,7 +27,7 @@ export class ThemeService { }); this.isSidebarOpen$.subscribe(isSidebarOpen => { this.isSidebarOpen = isSidebarOpen; - this.sidebarWidth$.next(isSidebarOpen ? '150px' : '50px'); + this.sidebarWidth$.next(isSidebarOpen ? '175px' : '75px'); }); this.sidebarWidth$.subscribe(sidebarWidth => { this.sidebarWidth = sidebarWidth; diff --git a/kdb-web/src/assets/i18n/de.json b/kdb-web/src/assets/i18n/de.json index 96fa7213ee..9eec0bf3a4 100644 --- a/kdb-web/src/assets/i18n/de.json +++ b/kdb-web/src/assets/i18n/de.json @@ -9,6 +9,9 @@ "dashboard": "Dashboard", "server": "Server", "server_empty": "Kein Server ausgewählt", + "settings": "Einstellungen", + "members": "Mitglieder", + "administration": "Administration", "config": "Konfiguration", "auth_user_list": "Benutzer" }, @@ -212,24 +215,8 @@ "Freitag", "Samstag" ], - "dayNamesShort": [ - "Son", - "Mon", - "Die", - "Mit", - "Don", - "Fre", - "Sam" - ], - "dayNamesMin": [ - "So", - "Mo", - "Di", - "Mi", - "Do", - "Fr", - "Sa" - ], + "dayNamesShort": ["Son", "Mon", "Die", "Mit", "Don", "Fre", "Sam"], + "dayNamesMin": ["So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"], "monthNames": [ "Januar", "Februar", @@ -267,4 +254,4 @@ "emptyMessage": "Keine Ergebnisse gefunden", "emptyFilterMessage": "Keine Ergebnisse gefunden" } -} \ No newline at end of file +} diff --git a/kdb-web/src/styles/primeng-fixes.scss b/kdb-web/src/styles/primeng-fixes.scss index 560ad4e34c..5bad03ee8e 100644 --- a/kdb-web/src/styles/primeng-fixes.scss +++ b/kdb-web/src/styles/primeng-fixes.scss @@ -6,14 +6,17 @@ } } -.p-menu { +.p-menu, +.p-panelmenu { background: none !important; border: none !important; width: auto !important; border-radius: 0px !important; padding: 0 !important; - .p-menuitem-link { + .p-menuitem-link, + .p-panelmenu-header > a, + .p-panelmenu-content .p-menuitem .p-menuitem-link { $distance: 10px; padding: $distance 0px $distance $distance !important; margin: 4px 0px 4px 6px !important; @@ -24,6 +27,31 @@ top: $headerHeight !important; } +.p-panelmenu { + .p-panelmenu-icon { + order: 1; // to be the first item on right side. + } + .p-menuitem-text { + flex-grow: 1; // to fill the whole space and push the icon to the end + } + + .p-panelmenu-header > a { + border: none !important; + border-radius: none !important; + font-weight: none !important; + transition: none !important; + } + + .p-panelmenu-content { + border: none !important; + background: none !important; + } + + .p-menuitem-text { + line-height: normal !important; + } +} + ui-menu .ui-menu-parent .ui-menu-child { width: 400px; /* exagerated !! */ } diff --git a/kdb-web/src/styles/themes/sh-edraft-dark-theme.scss b/kdb-web/src/styles/themes/sh-edraft-dark-theme.scss index 8fa192f1f0..6e0d8eb0d6 100644 --- a/kdb-web/src/styles/themes/sh-edraft-dark-theme.scss +++ b/kdb-web/src/styles/themes/sh-edraft-dark-theme.scss @@ -252,28 +252,43 @@ stroke: $primaryHeaderColor !important; } - .p-menu { + .p-menu, + .p-panelmenu { color: $primaryTextColor !important; .p-menuitem-link .p-menuitem-text, - .p-menuitem-link .p-menuitem-icon { + .p-menuitem-link .p-menuitem-icon, + .p-panelmenu-header > a { color: $primaryTextColor !important; + background: transparent !important; + font-size: 1rem !important; + font-weight: normal !important; } - .p-menuitem-link:focus { + .p-menuitem-link:focus, + .p-panelmenu-header > a:focus, + .p-panelmenu-content .p-menuitem .p-menuitem-link:focus { box-shadow: none !important; } - .p-menuitem-link:hover { + .p-menuitem-link:hover, + .p-panelmenu-header > a:hover, + .p-panelmenu-content .p-menuitem .p-menuitem-link:hover { background-color: $secondaryBackgroundColor !important; $border-radius: 20px; border-radius: $border-radius 0px 0px $border-radius; .p-menuitem-text, - .p-menuitem-icon { + .p-menuitem-icon, + .p-menuitem-text, + .p-panelmenu-icon { color: $primaryHeaderColor !important; } } + + .p-panelmenu-content { + margin: 5px 0px 5px 10px; + } } .p-menu-overlay { From 7760ee57254c8a1f409ab01d40509da3ea5e424c Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Tue, 18 Oct 2022 16:23:40 +0200 Subject: [PATCH 043/102] Update menu when server is selected #72 --- .../components/sidebar/sidebar.component.ts | 64 +++++++++++++------ .../dashboard/dashboard.component.ts | 7 +- .../server-dashboard.component.ts | 29 ++++----- .../view/server/server-routing.module.ts | 3 +- .../app/services/data/server.service.spec.ts | 16 +++++ .../src/app/services/data/server.service.ts | 23 +++++++ 6 files changed, 100 insertions(+), 42 deletions(-) create mode 100644 kdb-web/src/app/services/data/server.service.spec.ts create mode 100644 kdb-web/src/app/services/data/server.service.ts diff --git a/kdb-web/src/app/components/sidebar/sidebar.component.ts b/kdb-web/src/app/components/sidebar/sidebar.component.ts index f7815fbdcb..d43b42e522 100644 --- a/kdb-web/src/app/components/sidebar/sidebar.component.ts +++ b/kdb-web/src/app/components/sidebar/sidebar.component.ts @@ -1,8 +1,10 @@ import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; import { LangChangeEvent, TranslateService } from '@ngx-translate/core'; import { MenuItem } from 'primeng/api'; import { AuthRoles } from 'src/app/models/auth/auth-roles.enum'; import { AuthService } from 'src/app/services/auth/auth.service'; +import { ServerService } from 'src/app/services/data/server.service'; import { ThemeService } from 'src/app/services/theme/theme.service'; @Component({ @@ -13,13 +15,16 @@ import { ThemeService } from 'src/app/services/theme/theme.service'; export class SidebarComponent implements OnInit { isSidebarOpen: boolean = true; - menuItems!: MenuItem[]; + private serverId!: number; + constructor( private authService: AuthService, private translateService: TranslateService, - private themeService: ThemeService + private themeService: ThemeService, + private route: ActivatedRoute, + private serverService: ServerService ) { this.themeService.isSidebarOpen$.subscribe(value => { this.isSidebarOpen = value; @@ -29,6 +34,15 @@ export class SidebarComponent implements OnInit { this.translateService.onLangChange.subscribe((event: LangChangeEvent) => { this.setMenu(); }); + + this.serverService.server$.subscribe(server => { + if (!server) { + return; + } + + this.serverId = server.serverId; + this.setMenu(); + }); } ngOnInit(): void { @@ -39,30 +53,40 @@ export class SidebarComponent implements OnInit { this.authService.hasUserPermission(AuthRoles.Admin).then(hasPermission => { this.menuItems = []; this.menuItems = [ - { label: this.isSidebarOpen ? this.translateService.instant('sidebar.dashboard') : '', icon: 'pi pi-th-large', routerLink: 'dashboard' }, - - { - label: this.isSidebarOpen ? this.translateService.instant('sidebar.server') : '', icon: 'pi pi-server', items: [ - { label: this.isSidebarOpen ? this.translateService.instant('sidebar.settings') : '', icon: 'pi pi-cog', routerLink: 'server/id/settings' }, - { label: this.isSidebarOpen ? this.translateService.instant('sidebar.members') : '', icon: 'pi pi-user-edit', routerLink: 'server/id/members' }, - ] - }, + { label: this.isSidebarOpen ? this.translateService.instant('sidebar.dashboard') : '', icon: 'pi pi-th-large', routerLink: 'dashboard' } ]; - if (!hasPermission) { - return; + if (this.serverId) { + this.addServerMenu(); } - this.menuItems.push( - { - label: this.isSidebarOpen ? this.translateService.instant('sidebar.administration') : '', icon: 'pi pi-cog', items: [ - { label: this.isSidebarOpen ? this.translateService.instant('sidebar.config') : '', icon: 'pi pi-cog', routerLink: '/admin/settings' }, - { label: this.isSidebarOpen ? this.translateService.instant('sidebar.auth_user_list') : '', icon: 'pi pi-user-edit', routerLink: '/admin/users' }, - ] - }, - ); + if (hasPermission) { + this.addAdminMenu(); + } this.menuItems = this.menuItems.slice(); }); } + addServerMenu() { + this.menuItems.push( + { + label: this.isSidebarOpen ? this.translateService.instant('sidebar.server') : '', icon: 'pi pi-server', items: [ + { label: this.isSidebarOpen ? this.translateService.instant('sidebar.settings') : '', icon: 'pi pi-cog', routerLink: 'server/settings' }, + { label: this.isSidebarOpen ? this.translateService.instant('sidebar.members') : '', icon: 'pi pi-users', routerLink: 'server/members' }, + ] + } + ); + } + + addAdminMenu() { + this.menuItems.push( + { + label: this.isSidebarOpen ? this.translateService.instant('sidebar.administration') : '', icon: 'pi pi-cog', items: [ + { label: this.isSidebarOpen ? this.translateService.instant('sidebar.config') : '', icon: 'pi pi-cog', routerLink: '/admin/settings' }, + { label: this.isSidebarOpen ? this.translateService.instant('sidebar.auth_user_list') : '', icon: 'pi pi-user-edit', routerLink: '/admin/users' }, + ] + }, + ); + } + } diff --git a/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts index d149298e49..046e00c618 100644 --- a/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts +++ b/kdb-web/src/app/modules/view/dashboard/components/dashboard/dashboard.component.ts @@ -8,6 +8,7 @@ import { ServerDTO } from 'src/app/models/discord/server.dto'; import { ServerSelectCriterion } from 'src/app/models/selection/server/server-select-criterion.dto'; import { ConfirmationDialogService } from 'src/app/services/confirmation-dialog/confirmation-dialog.service'; import { DataService } from 'src/app/services/data/data.service'; +import { ServerService } from 'src/app/services/data/server.service'; import { SpinnerService } from 'src/app/services/spinner/spinner.service'; import { ToastService } from 'src/app/services/toast/toast.service'; @@ -41,7 +42,8 @@ export class DashboardComponent implements OnInit { private confirmDialog: ConfirmationDialogService, private fb: FormBuilder, private translate: TranslateService, - private router: Router + private router: Router, + private serverService: ServerService ) { } ngOnInit(): void { @@ -106,7 +108,8 @@ export class DashboardComponent implements OnInit { } selectServer(server: ServerDTO) { - this.router.navigate(['/server', server.serverId]); + this.serverService.server$.next(server); + this.router.navigate(['/server']); } } diff --git a/kdb-web/src/app/modules/view/server/server-dashboard/server-dashboard.component.ts b/kdb-web/src/app/modules/view/server/server-dashboard/server-dashboard.component.ts index 540ac8b639..158c771167 100644 --- a/kdb-web/src/app/modules/view/server/server-dashboard/server-dashboard.component.ts +++ b/kdb-web/src/app/modules/view/server/server-dashboard/server-dashboard.component.ts @@ -1,8 +1,8 @@ import { Component, OnInit } from '@angular/core'; import { ActivatedRoute, Router } from '@angular/router'; -import { catchError, throwError } from 'rxjs'; import { ServerDTO } from 'src/app/models/discord/server.dto'; import { DataService } from 'src/app/services/data/data.service'; +import { ServerService } from 'src/app/services/data/server.service'; import { SpinnerService } from 'src/app/services/spinner/spinner.service'; @Component({ @@ -19,27 +19,20 @@ export class ServerDashboardComponent implements OnInit { private route: ActivatedRoute, private router: Router, private data: DataService, - private spinner: SpinnerService + private spinner: SpinnerService, + private serverService: ServerService ) { } ngOnInit(): void { - this.route.params.subscribe(params => { - this.id = +params['id']; + this.spinner.showSpinner(); + if (!this.serverService.server$.value) { + this.spinner.hideSpinner(); + this.router.navigate(['/dashboard']); + return; + } - if (!this.id) { - this.router.navigate(['/dashboard']); - return; - } - - this.spinner.showSpinner(); - this.data.getServerByID(this.id).pipe(catchError(err => { - this.spinner.hideSpinner(); - return throwError(() => err); - })).subscribe(server => { - this.server = server; - this.spinner.hideSpinner(); - }); - }); + this.server = this.serverService.server$.value; + this.spinner.hideSpinner(); } } diff --git a/kdb-web/src/app/modules/view/server/server-routing.module.ts b/kdb-web/src/app/modules/view/server/server-routing.module.ts index 063beab12c..7b9f3ee70d 100644 --- a/kdb-web/src/app/modules/view/server/server-routing.module.ts +++ b/kdb-web/src/app/modules/view/server/server-routing.module.ts @@ -3,8 +3,7 @@ import { RouterModule, Routes } from '@angular/router'; import { ServerDashboardComponent } from './server-dashboard/server-dashboard.component'; const routes: Routes = [ - { path: '', component: ServerDashboardComponent }, - { path: ':id', component: ServerDashboardComponent } + { path: '', component: ServerDashboardComponent } ]; @NgModule({ diff --git a/kdb-web/src/app/services/data/server.service.spec.ts b/kdb-web/src/app/services/data/server.service.spec.ts new file mode 100644 index 0000000000..906c1601bb --- /dev/null +++ b/kdb-web/src/app/services/data/server.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { ServerService } from './server.service'; + +describe('ServerService', () => { + let service: ServerService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(ServerService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/services/data/server.service.ts b/kdb-web/src/app/services/data/server.service.ts new file mode 100644 index 0000000000..05d8673d46 --- /dev/null +++ b/kdb-web/src/app/services/data/server.service.ts @@ -0,0 +1,23 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Subject } from 'rxjs'; +import { ServerDTO } from 'src/app/models/discord/server.dto'; + +@Injectable({ + providedIn: 'root' +}) +export class ServerService { + + private server!: ServerDTO; + server$ = new BehaviorSubject(null); + + constructor() { + this.server$.subscribe(server => { + if (!server) { + return; + } + this.server = server; + }); + } + + +} From dee8e4fe74280c7594699bf5a1962522f76a8b8a Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Tue, 18 Oct 2022 16:36:24 +0200 Subject: [PATCH 044/102] Fixed themes #72 --- .../src/styles/themes/default-dark-theme.scss | 68 ++++++++++++++---- .../styles/themes/default-light-theme.scss | 70 +++++++++++++++---- .../styles/themes/sh-edraft-dark-theme.scss | 2 +- .../styles/themes/sh-edraft-light-theme.scss | 68 ++++++++++++++---- 4 files changed, 166 insertions(+), 42 deletions(-) diff --git a/kdb-web/src/styles/themes/default-dark-theme.scss b/kdb-web/src/styles/themes/default-dark-theme.scss index 1a3bd5d178..8a5b60fae4 100644 --- a/kdb-web/src/styles/themes/default-dark-theme.scss +++ b/kdb-web/src/styles/themes/default-dark-theme.scss @@ -15,16 +15,9 @@ $primaryErrorColor: #b00020; $secondaryErrorColor: #e94948; - $default-border: 1px solid $secondaryBackgroundColor3; + $default-border: 2px solid $secondaryBackgroundColor3; - background-color: $primaryBackgroundColor !important; - - html, - body { - margin: 0; - - font-size: 16px; - } + background-color: $primaryBackgroundColor; h1, h2 { @@ -122,6 +115,35 @@ .content-divider { border-bottom: $default-border; } + + .server-list-wrapper { + .server-filter { + } + + .server-count { + } + + .server-list { + .server { + border: $default-border; + border-radius: 15px; + + .logo { + img { + border-radius: 100%; + } + } + + .name { + color: $primaryHeaderColor; + } + + &:hover { + border-color: $primaryHeaderColor !important; + } + } + } + } } } } @@ -228,28 +250,43 @@ stroke: $primaryHeaderColor !important; } - .p-menu { + .p-menu, + .p-panelmenu { color: $primaryTextColor !important; .p-menuitem-link .p-menuitem-text, - .p-menuitem-link .p-menuitem-icon { + .p-menuitem-link .p-menuitem-icon, + .p-panelmenu-header > a { color: $primaryTextColor !important; + background: transparent !important; + font-size: 1rem !important; + font-weight: normal !important; } - .p-menuitem-link:focus { + .p-menuitem-link:focus, + .p-panelmenu-header > a:focus, + .p-panelmenu-content .p-menuitem .p-menuitem-link:focus { box-shadow: none !important; } - .p-menuitem-link:hover { + .p-menuitem-link:hover, + .p-panelmenu-header > a:hover, + .p-panelmenu-content .p-menuitem .p-menuitem-link:hover { background-color: $secondaryBackgroundColor !important; $border-radius: 20px; border-radius: $border-radius 0px 0px $border-radius; .p-menuitem-text, - .p-menuitem-icon { + .p-menuitem-icon, + .p-menuitem-text, + .p-panelmenu-icon { color: $primaryHeaderColor !important; } } + + .p-panelmenu-content { + margin: 5px 0px 5px 10px; + } } .p-menu-overlay { @@ -388,6 +425,9 @@ input, .p-password { + border-radius: 10px; + border: $default-border; + &:focus { box-shadow: none !important; } diff --git a/kdb-web/src/styles/themes/default-light-theme.scss b/kdb-web/src/styles/themes/default-light-theme.scss index 5993a05808..bc58a6f7a0 100644 --- a/kdb-web/src/styles/themes/default-light-theme.scss +++ b/kdb-web/src/styles/themes/default-light-theme.scss @@ -15,14 +15,9 @@ $primaryErrorColor: #b00020; $secondaryErrorColor: #e94948; - $default-border: 1px solid $secondaryBackgroundColor; + $default-border: 2px solid $secondaryBackgroundColor; - html, - body { - margin: 0; - - font-size: 16px; - } + background-color: $primaryBackgroundColor; h1, h2 { @@ -120,6 +115,35 @@ .content-divider { border-bottom: $default-border; } + + .server-list-wrapper { + .server-filter { + } + + .server-count { + } + + .server-list { + .server { + border: $default-border; + border-radius: 15px; + + .logo { + img { + border-radius: 100%; + } + } + + .name { + color: $primaryHeaderColor; + } + + &:hover { + border-color: $primaryHeaderColor !important; + } + } + } + } } } } @@ -226,28 +250,43 @@ stroke: $primaryHeaderColor !important; } - .p-menu { + .p-menu, + .p-panelmenu { color: $primaryTextColor !important; .p-menuitem-link .p-menuitem-text, - .p-menuitem-link .p-menuitem-icon { + .p-menuitem-link .p-menuitem-icon, + .p-panelmenu-header > a { color: $primaryTextColor !important; + background: transparent !important; + font-size: 1rem !important; + font-weight: normal !important; } - .p-menuitem-link:focus { + .p-menuitem-link:focus, + .p-panelmenu-header > a:focus, + .p-panelmenu-content .p-menuitem .p-menuitem-link:focus { box-shadow: none !important; } - .p-menuitem-link:hover { + .p-menuitem-link:hover, + .p-panelmenu-header > a:hover, + .p-panelmenu-content .p-menuitem .p-menuitem-link:hover { background-color: $secondaryBackgroundColor !important; $border-radius: 20px; border-radius: $border-radius 0px 0px $border-radius; - + .p-menuitem-text, - .p-menuitem-icon { + .p-menuitem-icon, + .p-menuitem-text, + .p-panelmenu-icon { color: $primaryHeaderColor !important; } } + + .p-panelmenu-content { + margin: 5px 0px 5px 10px; + } } .p-menu-overlay { @@ -386,6 +425,9 @@ input, .p-password { + border-radius: 10px; + border: $default-border; + &:focus { box-shadow: none !important; } @@ -430,7 +472,7 @@ color: $primaryTextColor !important; border: 0 !important; padding: 0px !important; - + &:hover { background-color: transparent !important; color: $primaryHeaderColor !important; diff --git a/kdb-web/src/styles/themes/sh-edraft-dark-theme.scss b/kdb-web/src/styles/themes/sh-edraft-dark-theme.scss index 6e0d8eb0d6..9e45019f04 100644 --- a/kdb-web/src/styles/themes/sh-edraft-dark-theme.scss +++ b/kdb-web/src/styles/themes/sh-edraft-dark-theme.scss @@ -17,7 +17,7 @@ $default-border: 2px solid $secondaryBackgroundColor3; - background-color: $primaryBackgroundColor !important; + background-color: $primaryBackgroundColor; h1, h2 { diff --git a/kdb-web/src/styles/themes/sh-edraft-light-theme.scss b/kdb-web/src/styles/themes/sh-edraft-light-theme.scss index fdd809491c..26c70cd5d0 100644 --- a/kdb-web/src/styles/themes/sh-edraft-light-theme.scss +++ b/kdb-web/src/styles/themes/sh-edraft-light-theme.scss @@ -15,14 +15,9 @@ $primaryErrorColor: #b00020; $secondaryErrorColor: #e94948; - $default-border: 1px solid $secondaryBackgroundColor; + $default-border: 2px solid $secondaryBackgroundColor; - html, - body { - margin: 0; - - font-size: 16px; - } + background-color: $primaryBackgroundColor; h1, h2 { @@ -121,6 +116,35 @@ border-bottom: $default-border; } } + + .server-list-wrapper { + .server-filter { + } + + .server-count { + } + + .server-list { + .server { + border: $default-border; + border-radius: 15px; + + .logo { + img { + border-radius: 100%; + } + } + + .name { + color: $primaryHeaderColor; + } + + &:hover { + border-color: $primaryHeaderColor !important; + } + } + } + } } } } @@ -226,28 +250,43 @@ stroke: $primaryHeaderColor !important; } - .p-menu { + .p-menu, + .p-panelmenu { color: $primaryTextColor !important; .p-menuitem-link .p-menuitem-text, - .p-menuitem-link .p-menuitem-icon { + .p-menuitem-link .p-menuitem-icon, + .p-panelmenu-header > a { color: $primaryTextColor !important; + background: transparent !important; + font-size: 1rem !important; + font-weight: normal !important; } - .p-menuitem-link:focus { + .p-menuitem-link:focus, + .p-panelmenu-header > a:focus, + .p-panelmenu-content .p-menuitem .p-menuitem-link:focus { box-shadow: none !important; } - .p-menuitem-link:hover { + .p-menuitem-link:hover, + .p-panelmenu-header > a:hover, + .p-panelmenu-content .p-menuitem .p-menuitem-link:hover { background-color: $secondaryBackgroundColor !important; $border-radius: 20px; border-radius: $border-radius 0px 0px $border-radius; .p-menuitem-text, - .p-menuitem-icon { + .p-menuitem-icon, + .p-menuitem-text, + .p-panelmenu-icon { color: $primaryHeaderColor !important; } } + + .p-panelmenu-content { + margin: 5px 0px 5px 10px; + } } .p-menu-overlay { @@ -386,6 +425,9 @@ input, .p-password { + border-radius: 10px; + border: $default-border; + &:focus { box-shadow: none !important; } @@ -430,7 +472,7 @@ color: $primaryTextColor !important; border: 0 !important; padding: 0px !important; - + &:hover { background-color: transparent !important; color: $primaryHeaderColor !important; From a51efa641d2cf70d2e57f6b8bb179e203a4c44fe Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Tue, 18 Oct 2022 18:04:53 +0200 Subject: [PATCH 045/102] Improved auth views and imrpoved default settings handling #70 --- kdb-web/.gitignore | 3 + kdb-web/package-lock.json | 607 +++++++++--------- kdb-web/src/app/app.component.ts | 32 +- .../app/components/header/header.component.ts | 1 - kdb-web/src/app/modules/auth/auth.module.ts | 8 +- .../auth-header/auth-header.component.html | 10 + .../auth-header/auth-header.component.scss | 0 .../auth-header/auth-header.component.spec.ts | 23 + .../auth-header/auth-header.component.ts | 83 +++ .../forget-password.component.html | 30 +- .../components/login/login.component.html | 22 +- .../registration/registration.component.html | 36 +- .../src/app/services/theme/theme.service.ts | 10 +- kdb-web/src/assets/i18n/de.json | 33 +- kdb-web/src/assets/i18n/en.json | 4 +- kdb-web/src/styles.scss | 16 +- kdb-web/src/styles/primeng-fixes.scss | 7 +- .../src/styles/themes/default-dark-theme.scss | 5 +- .../styles/themes/default-light-theme.scss | 5 +- .../styles/themes/sh-edraft-dark-theme.scss | 5 +- .../styles/themes/sh-edraft-light-theme.scss | 5 +- 21 files changed, 569 insertions(+), 376 deletions(-) create mode 100644 kdb-web/src/app/modules/auth/components/auth-header/auth-header.component.html create mode 100644 kdb-web/src/app/modules/auth/components/auth-header/auth-header.component.scss create mode 100644 kdb-web/src/app/modules/auth/components/auth-header/auth-header.component.spec.ts create mode 100644 kdb-web/src/app/modules/auth/components/auth-header/auth-header.component.ts diff --git a/kdb-web/.gitignore b/kdb-web/.gitignore index c03363f80d..50db1a9436 100644 --- a/kdb-web/.gitignore +++ b/kdb-web/.gitignore @@ -41,3 +41,6 @@ testem.log # System files .DS_Store Thumbs.db + +ignore +ignore/* \ No newline at end of file diff --git a/kdb-web/package-lock.json b/kdb-web/package-lock.json index 273efa031e..6094a76e69 100644 --- a/kdb-web/package-lock.json +++ b/kdb-web/package-lock.json @@ -64,12 +64,12 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1402.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1402.5.tgz", - "integrity": "sha512-vtJEwB51UEY1Q7FCI7xGLdhdb2SRTtI1Qs0or95momn85NuxlaMQsXK1Wxu9/EwtWKZK8dXePXbB/hpiNt61JQ==", + "version": "0.1402.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1402.6.tgz", + "integrity": "sha512-qTmPBD7fBXBtlSapGLUEcJvRuL/O556zCFFpH3kSlzPNTYxi2falBjGY+4aG+078RXT1vVZtFsvRTart6VbhAg==", "dev": true, "dependencies": { - "@angular-devkit/core": "14.2.5", + "@angular-devkit/core": "14.2.6", "rxjs": "6.6.7" }, "engines": { @@ -97,15 +97,15 @@ "dev": true }, "node_modules/@angular-devkit/build-angular": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.2.5.tgz", - "integrity": "sha512-jSgH11E+zs1C24lXj7R/PgXsTUpoYoMr1GtO6mpVROgXL5czVlL+b/B1p2HwbcAKuI9WXb48X6OZ6fOZhDQlSg==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.2.6.tgz", + "integrity": "sha512-XtaUwb3aZ8S0vl0y9bmbdFOH0KQCQ778twFH+ZfHW2BcPYtQz2Cy2rcVKXBQ850RyC0GxgMPfco6OGQndPpizg==", "dev": true, "dependencies": { "@ampproject/remapping": "2.2.0", - "@angular-devkit/architect": "0.1402.5", - "@angular-devkit/build-webpack": "0.1402.5", - "@angular-devkit/core": "14.2.5", + "@angular-devkit/architect": "0.1402.6", + "@angular-devkit/build-webpack": "0.1402.6", + "@angular-devkit/core": "14.2.6", "@babel/core": "7.18.10", "@babel/generator": "7.18.12", "@babel/helper-annotate-as-pure": "7.18.6", @@ -116,7 +116,7 @@ "@babel/runtime": "7.18.9", "@babel/template": "7.18.10", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "14.2.5", + "@ngtools/webpack": "14.2.6", "ansi-colors": "4.1.3", "babel-loader": "8.2.5", "babel-plugin-istanbul": "6.1.1", @@ -223,12 +223,12 @@ "dev": true }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1402.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.5.tgz", - "integrity": "sha512-h+o0GZD9iATwWjaTiUR0lJ3QZ9twUOJ1sotRchXHzAXMuaDk8wqqPriL5S0qDMlA2QqpNt4OD9rodUCRwae7fw==", + "version": "0.1402.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.6.tgz", + "integrity": "sha512-gKsDxQ9pze0N1qDM0kdM4FfwpkjSOb0bQzqjZi7wTfrh/WGIQMCjG9CRwWT+Z289ZKaTpcQDPsDtOSo5QpKNDg==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1402.5", + "@angular-devkit/architect": "0.1402.6", "rxjs": "6.6.7" }, "engines": { @@ -260,9 +260,9 @@ "dev": true }, "node_modules/@angular-devkit/core": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.5.tgz", - "integrity": "sha512-lSje+HX0fx9Y2A4k63jVHrWdGT4wellhwcZpTCv9P6LvdfTkAlrfra3TaYhUPjavCsPwlRC/VVQN3Qkzk5m6gA==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.6.tgz", + "integrity": "sha512-qtRSdRm/h7C3ya04PJTDgQXV6mM8Y4RakANX1GTSXetCf9AVSxg74NJX76DWUgiHT4JiPYnJgJU6Hr/L0H6JOQ==", "dev": true, "dependencies": { "ajv": "8.11.0", @@ -381,9 +381,9 @@ "dev": true }, "node_modules/@angular/animations": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-14.2.5.tgz", - "integrity": "sha512-4BhR9jSjgIwoK/alu7FSwSU5SxISMVFBAl/4cEYchfCqnflMNkZ8WwRVKTQjyeuYW5KtQTw9jRNp4tGK1YQWYw==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-14.2.6.tgz", + "integrity": "sha512-Tmb3Jj016j8m8OOGSk/ReL0b+OuUCMj0KQansk3C4pCpH9oPF67Vnm0fmVC2wYjjsSS/iDgl4kaDW740wfPGNQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -391,7 +391,7 @@ "node": "^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/core": "14.2.5" + "@angular/core": "14.2.6" } }, "node_modules/@angular/cli": { @@ -514,9 +514,9 @@ "dev": true }, "node_modules/@angular/common": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.2.5.tgz", - "integrity": "sha512-v2fIK6imfMkUvYNjZQO+drE39QO3eSS95Yy7UN+6inb47DkAfzx6hipA9zKrMENjsS3kDv1d7cgDHE7WuOCzIw==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.2.6.tgz", + "integrity": "sha512-WNX7xe8LKP5DHPlae+c77PDwj0iIAAPIe1lWbhQysyi8uttbtL9VVP2XTFuQ3E6oVHJr+0IR0LMVGJ+a8i6zsw==", "dependencies": { "tslib": "^2.3.0" }, @@ -524,14 +524,14 @@ "node": "^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/core": "14.2.5", + "@angular/core": "14.2.6", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-14.2.5.tgz", - "integrity": "sha512-L7d2/D6o9wlB2ugqRYpev6a8JntqS+7lF2o6z8y7RR2YAlAu71nq0BDsQez4/aSCK3HnDq0yhEnns7vcmOq/jA==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-14.2.6.tgz", + "integrity": "sha512-XtmJRNQQ/bUcRjB6jG67km3EPug8frnHH50sLqxye+cljCzWQpzFN/Qr1z0abuzEX8OC4alqxCDCFgTFyyVkaQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -539,7 +539,7 @@ "node": "^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/core": "14.2.5" + "@angular/core": "14.2.6" }, "peerDependenciesMeta": { "@angular/core": { @@ -548,9 +548,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-14.2.5.tgz", - "integrity": "sha512-3GYzTPw96TfJjw7Aso+f+uN6VFBWedqRATUQ6v+BAEyZIboirdLI1JQFOcCfuKWUM2B48RW+pdIduZmG3ckotA==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-14.2.6.tgz", + "integrity": "sha512-zKnpZ5WDbM31dwr5GDAbCblMIEUzWSglUyqCxJfbCg21dE0EuLfd/WzsROgM2TucOtCT5xNipqz4bc+wdEOIgQ==", "dev": true, "dependencies": { "@babel/core": "^7.17.2", @@ -573,14 +573,14 @@ "node": "^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/compiler": "14.2.5", + "@angular/compiler": "14.2.6", "typescript": ">=4.6.2 <4.9" } }, "node_modules/@angular/core": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.2.5.tgz", - "integrity": "sha512-Ok78Abq0puMGlolvNVzKFvsX7ePDkyxpZzztDzXDdRA4x4o6bAuuDG9Y7Wab2+wsdY6NktO+dFQjq1UBWClgSg==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.2.6.tgz", + "integrity": "sha512-fEIz7E488X03tLIqmWQRpahxRRU2SMjb9i/rMUjMQJkbppJC3cykl31bCYzeixNO+zpE55GPGuQX2qI/yDenZA==", "dependencies": { "tslib": "^2.3.0" }, @@ -593,9 +593,9 @@ } }, "node_modules/@angular/forms": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-14.2.5.tgz", - "integrity": "sha512-aMH5Vrftny0KF0XzWQIGfHoI0LVQ2aatpWzdUWiUqBeX/Q+ucmxeP5rZyKtUsi0flETWxdRZSBTjbXZ3dsIcTA==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-14.2.6.tgz", + "integrity": "sha512-t7Hd9RMnHbXRTdH/H8h8ZC3PsK1U4rH+XYaIbQNcys/XSf1uRFHx9MWqkwS5hoQEFOxkFSX5dRv2xSnHtxfq5w==", "dependencies": { "tslib": "^2.3.0" }, @@ -603,16 +603,16 @@ "node": "^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/common": "14.2.5", - "@angular/core": "14.2.5", - "@angular/platform-browser": "14.2.5", + "@angular/common": "14.2.6", + "@angular/core": "14.2.6", + "@angular/platform-browser": "14.2.6", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/platform-browser": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-14.2.5.tgz", - "integrity": "sha512-FDZm23N9veSEouQX1YuZUjv7Nillroi+v0VbN1x5iPpFZEudaoZYT3A7bpJwdlxUx/4rGS0caaXNhN3CowtIeQ==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-14.2.6.tgz", + "integrity": "sha512-KQUN4YVYEK5NOL7QFnDulQta6tm9rPh/mruX/XCLkSmoRMlFBmsHyjx+VJBnBNUbUxNsBj7kknifOu9PqDgAWg==", "dependencies": { "tslib": "^2.3.0" }, @@ -620,9 +620,9 @@ "node": "^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/animations": "14.2.5", - "@angular/common": "14.2.5", - "@angular/core": "14.2.5" + "@angular/animations": "14.2.6", + "@angular/common": "14.2.6", + "@angular/core": "14.2.6" }, "peerDependenciesMeta": { "@angular/animations": { @@ -631,9 +631,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-14.2.5.tgz", - "integrity": "sha512-7W8oLs8YEGRr8izgUlpHgBfg3vUb5H0yicTHJY4zIqHJJbG1rTl46CjULaMjYM/FWcS8o7y6XJJcHx0c7pKNsw==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-14.2.6.tgz", + "integrity": "sha512-SlWEYLED4ST1AFfgeB8SyKLVJYp36XT+3Vw3yDrObsthzXCiFAuYHQZfSWgT1Sfx3uFqEdN7nskJqD05wN3mQg==", "dependencies": { "tslib": "^2.3.0" }, @@ -641,16 +641,16 @@ "node": "^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/common": "14.2.5", - "@angular/compiler": "14.2.5", - "@angular/core": "14.2.5", - "@angular/platform-browser": "14.2.5" + "@angular/common": "14.2.6", + "@angular/compiler": "14.2.6", + "@angular/core": "14.2.6", + "@angular/platform-browser": "14.2.6" } }, "node_modules/@angular/router": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-14.2.5.tgz", - "integrity": "sha512-AUHcr9Lln7emJ/aete08UoqWQFZOLH1MhuP78r2pixvnNiZ9C8hcevX1rGGax0Po/Gy4PSJ4wnFhZPgifqCguQ==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-14.2.6.tgz", + "integrity": "sha512-Vz1kadGSqA7ZCZQ2woNbSBPMdiE5eTZv8cGympaFnFQQUzQTQ6zi22wY4RzovDk5Lw+EQkvOmaW2864LDzDeug==", "dependencies": { "tslib": "^2.3.0" }, @@ -658,9 +658,9 @@ "node": "^14.15.0 || >=16.10.0" }, "peerDependencies": { - "@angular/common": "14.2.5", - "@angular/core": "14.2.5", - "@angular/platform-browser": "14.2.5", + "@angular/common": "14.2.6", + "@angular/core": "14.2.6", + "@angular/platform-browser": "14.2.6", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -2319,9 +2319,9 @@ } }, "node_modules/@babel/traverse/node_modules/@babel/generator": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.4.tgz", - "integrity": "sha512-5T2lY5vXqS+5UEit/5TwcIUeCnwgCljcF8IQRT6XRQPBrvLeq5V8W+URv+GvwoF3FP8tkhp++evVyDzkDGzNmA==", + "version": "7.19.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.5.tgz", + "integrity": "sha512-DxbNz9Lz4aMZ99qPpO1raTbcrI1ZeYh+9NR9qhfkQIbFtVEqotHojEBxHzmxhVONkGt6VyrqVQcgpefMy9pqcg==", "dev": true, "dependencies": { "@babel/types": "^7.19.4", @@ -2768,9 +2768,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.16", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.16.tgz", - "integrity": "sha512-LCQ+NeThyJ4k1W2d+vIKdxuSt9R3pQSZ4P92m7EakaYuXcVWbHuT5bjNcqLd4Rdgi6xYWYDvBJZJLZSLanjDcA==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "3.1.0", @@ -2784,9 +2784,9 @@ "dev": true }, "node_modules/@microsoft/signalr": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-6.0.9.tgz", - "integrity": "sha512-DGVYe3ycT2PfRU7m3xCbv1HjhvClKl2VB1HyFlvf8SqBGXz3Cx+oalNWGYrGIgADA6Q2xaB4GaDmDdprTa2U0Q==", + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-6.0.10.tgz", + "integrity": "sha512-ND9LiIYac+ZDgCgW2QzpNfe9BTiOtjc2AX/2GtFIhRGhEzx5CixcNANg2VGj27IAxycAPPnEoy7+QA31Eil7QQ==", "dependencies": { "abort-controller": "^3.0.0", "eventsource": "^1.0.7", @@ -2795,30 +2795,10 @@ "ws": "^7.4.5" } }, - "node_modules/@microsoft/signalr/node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "engines": { - "node": ">=8.3.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, "node_modules/@ngtools/webpack": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.5.tgz", - "integrity": "sha512-Thwq1WyOOq1PIWMcjAAqKI1hbvGC0ywxbNoDadOlWpEFm6k0dvXC6Zm9lnVkePjxlPfagvbnv55+Lv9Vmygc1g==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.6.tgz", + "integrity": "sha512-HdfoHLGPzyP135BOlvTQcpeWisVfiH0u40YNTBVK3QAsrLnY17e2QG5BWBOrVYipRu1975cZtTC9rPjcCY8aLQ==", "dev": true, "engines": { "node": "^14.15.0 || >=16.10.0", @@ -3220,9 +3200,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.8.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz", - "integrity": "sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==", + "version": "18.11.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.0.tgz", + "integrity": "sha512-IOXCvVRToe7e0ny7HpT/X9Rb2RYtElG1a+VshjwT00HxrM2dWBApHQoqsI6WiY7Q03vdf2bCrIGzVrkF/5t10w==", "dev": true }, "node_modules/@types/parse-json": { @@ -4170,9 +4150,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001418", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz", - "integrity": "sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==", + "version": "1.0.30001421", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001421.tgz", + "integrity": "sha512-Sw4eLbgUJAEhjLs1Fa+mk45sidp1wRn5y6GtDpHGBaNJ9OCDJaVh2tIaWWUnGfuXfKf1JCBaIarak3FkVAvEeA==", "dev": true, "funding": [ { @@ -4422,6 +4402,12 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -4485,26 +4471,6 @@ "node": ">= 0.6" } }, - "node_modules/content-disposition/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/content-type": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", @@ -4515,13 +4481,10 @@ } }, "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true }, "node_modules/cookie": { "version": "0.4.2", @@ -4872,9 +4835,9 @@ } }, "node_modules/cssdb": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.0.1.tgz", - "integrity": "sha512-pT3nzyGM78poCKLAEy2zWIVX2hikq6dIrjuZzLV98MumBg+xMTNYfHx7paUlfiRTgg91O/vR889CIf+qiv79Rw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.0.2.tgz", + "integrity": "sha512-Vm4b6P/PifADu0a76H0DKRNVWq3Rq9xa/Nx6oEMUBJlwTUuZoZ3dkZxo8Gob3UEL53Cq+Ma1GBgISed6XEBs3w==", "dev": true, "funding": { "type": "opencollective", @@ -5132,9 +5095,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.276", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.276.tgz", - "integrity": "sha512-EpuHPqu8YhonqLBXHoU6hDJCD98FCe6KDoet3/gY1qsQ6usjJoHqBH2YIVs8FXaAtHwVL8Uqa/fsYao/vq9VWQ==", + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", "dev": true }, "node_modules/emoji-regex": { @@ -5215,6 +5178,26 @@ "xmlhttprequest-ssl": "~2.0.0" } }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/engine.io-parser": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", @@ -5223,6 +5206,27 @@ "node": ">=10.0.0" } }, + "node_modules/engine.io/node_modules/ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/enhanced-resolve": { "version": "5.10.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", @@ -5911,26 +5915,6 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "node_modules/express/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/express/node_modules/statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -6493,6 +6477,12 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/hpack.js/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "node_modules/hpack.js/node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -8205,10 +8195,13 @@ } }, "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/minipass": { "version": "3.3.4", @@ -10602,10 +10595,24 @@ } }, "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, "node_modules/safer-buffer": { "version": "2.1.2", @@ -11015,9 +11022,9 @@ } }, "node_modules/socket.io": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.2.tgz", - "integrity": "sha512-6fCnk4ARMPZN448+SQcnn1u8OHUC72puJcNtSgg2xS34Cu7br1gQ09YKkO1PFfDn/wyUE9ZgMAwosJed003+NQ==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.3.tgz", + "integrity": "sha512-zdpnnKU+H6mOp7nYRXH4GNv1ux6HL6+lHL8g7Ds7Lj8CkdK1jJK/dlwsKDculbyOHifcJ0Pr/yeXnZQ5GeFrcg==", "dev": true, "dependencies": { "accepts": "~1.3.4", @@ -11290,26 +11297,6 @@ "safe-buffer": "~5.2.0" } }, - "node_modules/string_decoder/node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -11815,9 +11802,9 @@ } }, "node_modules/ua-parser-js": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", - "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", + "version": "0.7.32", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.32.tgz", + "integrity": "sha512-f9BESNVhzlhEFf2CHMSj40NWOjYPl1YKYbrvIr/hFTDEmLq7SRbWvm7FcdcpCYT95zrOhC7gZSxjdnnTpBcwVw==", "dev": true, "funding": [ { @@ -12445,11 +12432,11 @@ "dev": true }, "node_modules/ws": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "engines": { - "node": ">=10.0.0" + "node": ">=8.3.0" }, "peerDependencies": { "bufferutil": "^4.0.1", @@ -12559,12 +12546,12 @@ } }, "@angular-devkit/architect": { - "version": "0.1402.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1402.5.tgz", - "integrity": "sha512-vtJEwB51UEY1Q7FCI7xGLdhdb2SRTtI1Qs0or95momn85NuxlaMQsXK1Wxu9/EwtWKZK8dXePXbB/hpiNt61JQ==", + "version": "0.1402.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1402.6.tgz", + "integrity": "sha512-qTmPBD7fBXBtlSapGLUEcJvRuL/O556zCFFpH3kSlzPNTYxi2falBjGY+4aG+078RXT1vVZtFsvRTart6VbhAg==", "dev": true, "requires": { - "@angular-devkit/core": "14.2.5", + "@angular-devkit/core": "14.2.6", "rxjs": "6.6.7" }, "dependencies": { @@ -12586,15 +12573,15 @@ } }, "@angular-devkit/build-angular": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.2.5.tgz", - "integrity": "sha512-jSgH11E+zs1C24lXj7R/PgXsTUpoYoMr1GtO6mpVROgXL5czVlL+b/B1p2HwbcAKuI9WXb48X6OZ6fOZhDQlSg==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-14.2.6.tgz", + "integrity": "sha512-XtaUwb3aZ8S0vl0y9bmbdFOH0KQCQ778twFH+ZfHW2BcPYtQz2Cy2rcVKXBQ850RyC0GxgMPfco6OGQndPpizg==", "dev": true, "requires": { "@ampproject/remapping": "2.2.0", - "@angular-devkit/architect": "0.1402.5", - "@angular-devkit/build-webpack": "0.1402.5", - "@angular-devkit/core": "14.2.5", + "@angular-devkit/architect": "0.1402.6", + "@angular-devkit/build-webpack": "0.1402.6", + "@angular-devkit/core": "14.2.6", "@babel/core": "7.18.10", "@babel/generator": "7.18.12", "@babel/helper-annotate-as-pure": "7.18.6", @@ -12605,7 +12592,7 @@ "@babel/runtime": "7.18.9", "@babel/template": "7.18.10", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "14.2.5", + "@ngtools/webpack": "14.2.6", "ansi-colors": "4.1.3", "babel-loader": "8.2.5", "babel-plugin-istanbul": "6.1.1", @@ -12676,12 +12663,12 @@ } }, "@angular-devkit/build-webpack": { - "version": "0.1402.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.5.tgz", - "integrity": "sha512-h+o0GZD9iATwWjaTiUR0lJ3QZ9twUOJ1sotRchXHzAXMuaDk8wqqPriL5S0qDMlA2QqpNt4OD9rodUCRwae7fw==", + "version": "0.1402.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1402.6.tgz", + "integrity": "sha512-gKsDxQ9pze0N1qDM0kdM4FfwpkjSOb0bQzqjZi7wTfrh/WGIQMCjG9CRwWT+Z289ZKaTpcQDPsDtOSo5QpKNDg==", "dev": true, "requires": { - "@angular-devkit/architect": "0.1402.5", + "@angular-devkit/architect": "0.1402.6", "rxjs": "6.6.7" }, "dependencies": { @@ -12703,9 +12690,9 @@ } }, "@angular-devkit/core": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.5.tgz", - "integrity": "sha512-lSje+HX0fx9Y2A4k63jVHrWdGT4wellhwcZpTCv9P6LvdfTkAlrfra3TaYhUPjavCsPwlRC/VVQN3Qkzk5m6gA==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-14.2.6.tgz", + "integrity": "sha512-qtRSdRm/h7C3ya04PJTDgQXV6mM8Y4RakANX1GTSXetCf9AVSxg74NJX76DWUgiHT4JiPYnJgJU6Hr/L0H6JOQ==", "dev": true, "requires": { "ajv": "8.11.0", @@ -12788,9 +12775,9 @@ } }, "@angular/animations": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-14.2.5.tgz", - "integrity": "sha512-4BhR9jSjgIwoK/alu7FSwSU5SxISMVFBAl/4cEYchfCqnflMNkZ8WwRVKTQjyeuYW5KtQTw9jRNp4tGK1YQWYw==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-14.2.6.tgz", + "integrity": "sha512-Tmb3Jj016j8m8OOGSk/ReL0b+OuUCMj0KQansk3C4pCpH9oPF67Vnm0fmVC2wYjjsSS/iDgl4kaDW740wfPGNQ==", "requires": { "tslib": "^2.3.0" } @@ -12882,25 +12869,25 @@ } }, "@angular/common": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.2.5.tgz", - "integrity": "sha512-v2fIK6imfMkUvYNjZQO+drE39QO3eSS95Yy7UN+6inb47DkAfzx6hipA9zKrMENjsS3kDv1d7cgDHE7WuOCzIw==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-14.2.6.tgz", + "integrity": "sha512-WNX7xe8LKP5DHPlae+c77PDwj0iIAAPIe1lWbhQysyi8uttbtL9VVP2XTFuQ3E6oVHJr+0IR0LMVGJ+a8i6zsw==", "requires": { "tslib": "^2.3.0" } }, "@angular/compiler": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-14.2.5.tgz", - "integrity": "sha512-L7d2/D6o9wlB2ugqRYpev6a8JntqS+7lF2o6z8y7RR2YAlAu71nq0BDsQez4/aSCK3HnDq0yhEnns7vcmOq/jA==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-14.2.6.tgz", + "integrity": "sha512-XtmJRNQQ/bUcRjB6jG67km3EPug8frnHH50sLqxye+cljCzWQpzFN/Qr1z0abuzEX8OC4alqxCDCFgTFyyVkaQ==", "requires": { "tslib": "^2.3.0" } }, "@angular/compiler-cli": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-14.2.5.tgz", - "integrity": "sha512-3GYzTPw96TfJjw7Aso+f+uN6VFBWedqRATUQ6v+BAEyZIboirdLI1JQFOcCfuKWUM2B48RW+pdIduZmG3ckotA==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-14.2.6.tgz", + "integrity": "sha512-zKnpZ5WDbM31dwr5GDAbCblMIEUzWSglUyqCxJfbCg21dE0EuLfd/WzsROgM2TucOtCT5xNipqz4bc+wdEOIgQ==", "dev": true, "requires": { "@babel/core": "^7.17.2", @@ -12916,41 +12903,41 @@ } }, "@angular/core": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.2.5.tgz", - "integrity": "sha512-Ok78Abq0puMGlolvNVzKFvsX7ePDkyxpZzztDzXDdRA4x4o6bAuuDG9Y7Wab2+wsdY6NktO+dFQjq1UBWClgSg==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-14.2.6.tgz", + "integrity": "sha512-fEIz7E488X03tLIqmWQRpahxRRU2SMjb9i/rMUjMQJkbppJC3cykl31bCYzeixNO+zpE55GPGuQX2qI/yDenZA==", "requires": { "tslib": "^2.3.0" } }, "@angular/forms": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-14.2.5.tgz", - "integrity": "sha512-aMH5Vrftny0KF0XzWQIGfHoI0LVQ2aatpWzdUWiUqBeX/Q+ucmxeP5rZyKtUsi0flETWxdRZSBTjbXZ3dsIcTA==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-14.2.6.tgz", + "integrity": "sha512-t7Hd9RMnHbXRTdH/H8h8ZC3PsK1U4rH+XYaIbQNcys/XSf1uRFHx9MWqkwS5hoQEFOxkFSX5dRv2xSnHtxfq5w==", "requires": { "tslib": "^2.3.0" } }, "@angular/platform-browser": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-14.2.5.tgz", - "integrity": "sha512-FDZm23N9veSEouQX1YuZUjv7Nillroi+v0VbN1x5iPpFZEudaoZYT3A7bpJwdlxUx/4rGS0caaXNhN3CowtIeQ==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-14.2.6.tgz", + "integrity": "sha512-KQUN4YVYEK5NOL7QFnDulQta6tm9rPh/mruX/XCLkSmoRMlFBmsHyjx+VJBnBNUbUxNsBj7kknifOu9PqDgAWg==", "requires": { "tslib": "^2.3.0" } }, "@angular/platform-browser-dynamic": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-14.2.5.tgz", - "integrity": "sha512-7W8oLs8YEGRr8izgUlpHgBfg3vUb5H0yicTHJY4zIqHJJbG1rTl46CjULaMjYM/FWcS8o7y6XJJcHx0c7pKNsw==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-14.2.6.tgz", + "integrity": "sha512-SlWEYLED4ST1AFfgeB8SyKLVJYp36XT+3Vw3yDrObsthzXCiFAuYHQZfSWgT1Sfx3uFqEdN7nskJqD05wN3mQg==", "requires": { "tslib": "^2.3.0" } }, "@angular/router": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-14.2.5.tgz", - "integrity": "sha512-AUHcr9Lln7emJ/aete08UoqWQFZOLH1MhuP78r2pixvnNiZ9C8hcevX1rGGax0Po/Gy4PSJ4wnFhZPgifqCguQ==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-14.2.6.tgz", + "integrity": "sha512-Vz1kadGSqA7ZCZQ2woNbSBPMdiE5eTZv8cGympaFnFQQUzQTQ6zi22wY4RzovDk5Lw+EQkvOmaW2864LDzDeug==", "requires": { "tslib": "^2.3.0" } @@ -14114,9 +14101,9 @@ }, "dependencies": { "@babel/generator": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.4.tgz", - "integrity": "sha512-5T2lY5vXqS+5UEit/5TwcIUeCnwgCljcF8IQRT6XRQPBrvLeq5V8W+URv+GvwoF3FP8tkhp++evVyDzkDGzNmA==", + "version": "7.19.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.5.tgz", + "integrity": "sha512-DxbNz9Lz4aMZ99qPpO1raTbcrI1ZeYh+9NR9qhfkQIbFtVEqotHojEBxHzmxhVONkGt6VyrqVQcgpefMy9pqcg==", "dev": true, "requires": { "@babel/types": "^7.19.4", @@ -14380,9 +14367,9 @@ "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.16", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.16.tgz", - "integrity": "sha512-LCQ+NeThyJ4k1W2d+vIKdxuSt9R3pQSZ4P92m7EakaYuXcVWbHuT5bjNcqLd4Rdgi6xYWYDvBJZJLZSLanjDcA==", + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", "dev": true, "requires": { "@jridgewell/resolve-uri": "3.1.0", @@ -14396,29 +14383,21 @@ "dev": true }, "@microsoft/signalr": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-6.0.9.tgz", - "integrity": "sha512-DGVYe3ycT2PfRU7m3xCbv1HjhvClKl2VB1HyFlvf8SqBGXz3Cx+oalNWGYrGIgADA6Q2xaB4GaDmDdprTa2U0Q==", + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/@microsoft/signalr/-/signalr-6.0.10.tgz", + "integrity": "sha512-ND9LiIYac+ZDgCgW2QzpNfe9BTiOtjc2AX/2GtFIhRGhEzx5CixcNANg2VGj27IAxycAPPnEoy7+QA31Eil7QQ==", "requires": { "abort-controller": "^3.0.0", "eventsource": "^1.0.7", "fetch-cookie": "^0.11.0", "node-fetch": "^2.6.7", "ws": "^7.4.5" - }, - "dependencies": { - "ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "requires": {} - } } }, "@ngtools/webpack": { - "version": "14.2.5", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.5.tgz", - "integrity": "sha512-Thwq1WyOOq1PIWMcjAAqKI1hbvGC0ywxbNoDadOlWpEFm6k0dvXC6Zm9lnVkePjxlPfagvbnv55+Lv9Vmygc1g==", + "version": "14.2.6", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-14.2.6.tgz", + "integrity": "sha512-HdfoHLGPzyP135BOlvTQcpeWisVfiH0u40YNTBVK3QAsrLnY17e2QG5BWBOrVYipRu1975cZtTC9rPjcCY8aLQ==", "dev": true, "requires": {} }, @@ -14740,9 +14719,9 @@ "dev": true }, "@types/node": { - "version": "18.8.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.8.3.tgz", - "integrity": "sha512-0os9vz6BpGwxGe9LOhgP/ncvYN5Tx1fNcd2TM3rD/aCGBkysb+ZWpXEocG24h6ZzOi13+VB8HndAQFezsSOw1w==", + "version": "18.11.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.0.tgz", + "integrity": "sha512-IOXCvVRToe7e0ny7HpT/X9Rb2RYtElG1a+VshjwT00HxrM2dWBApHQoqsI6WiY7Q03vdf2bCrIGzVrkF/5t10w==", "dev": true }, "@types/parse-json": { @@ -15506,9 +15485,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001418", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz", - "integrity": "sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==", + "version": "1.0.30001421", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001421.tgz", + "integrity": "sha512-Sw4eLbgUJAEhjLs1Fa+mk45sidp1wRn5y6GtDpHGBaNJ9OCDJaVh2tIaWWUnGfuXfKf1JCBaIarak3FkVAvEeA==", "dev": true }, "chalk": { @@ -15694,6 +15673,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true } } }, @@ -15751,14 +15736,6 @@ "dev": true, "requires": { "safe-buffer": "5.2.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - } } }, "content-type": { @@ -15768,13 +15745,10 @@ "dev": true }, "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true }, "cookie": { "version": "0.4.2", @@ -16020,9 +15994,9 @@ "dev": true }, "cssdb": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.0.1.tgz", - "integrity": "sha512-pT3nzyGM78poCKLAEy2zWIVX2hikq6dIrjuZzLV98MumBg+xMTNYfHx7paUlfiRTgg91O/vR889CIf+qiv79Rw==", + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cssdb/-/cssdb-7.0.2.tgz", + "integrity": "sha512-Vm4b6P/PifADu0a76H0DKRNVWq3Rq9xa/Nx6oEMUBJlwTUuZoZ3dkZxo8Gob3UEL53Cq+Ma1GBgISed6XEBs3w==", "dev": true }, "cssesc": { @@ -16207,9 +16181,9 @@ "dev": true }, "electron-to-chromium": { - "version": "1.4.276", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.276.tgz", - "integrity": "sha512-EpuHPqu8YhonqLBXHoU6hDJCD98FCe6KDoet3/gY1qsQ6usjJoHqBH2YIVs8FXaAtHwVL8Uqa/fsYao/vq9VWQ==", + "version": "1.4.284", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", + "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==", "dev": true }, "emoji-regex": { @@ -16266,6 +16240,15 @@ "debug": "~4.3.1", "engine.io-parser": "~5.0.3", "ws": "~8.2.3" + }, + "dependencies": { + "ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "dev": true, + "requires": {} + } } }, "engine.io-client": { @@ -16278,6 +16261,14 @@ "engine.io-parser": "~5.0.3", "ws": "~8.2.3", "xmlhttprequest-ssl": "~2.0.0" + }, + "dependencies": { + "ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "requires": {} + } } }, "engine.io-parser": { @@ -16715,12 +16706,6 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - }, "statuses": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", @@ -17151,6 +17136,12 @@ "util-deprecate": "~1.0.1" } }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -18440,9 +18431,9 @@ } }, "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", "dev": true }, "minipass": { @@ -20125,9 +20116,9 @@ } }, "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, "safer-buffer": { @@ -20443,9 +20434,9 @@ "dev": true }, "socket.io": { - "version": "4.5.2", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.2.tgz", - "integrity": "sha512-6fCnk4ARMPZN448+SQcnn1u8OHUC72puJcNtSgg2xS34Cu7br1gQ09YKkO1PFfDn/wyUE9ZgMAwosJed003+NQ==", + "version": "4.5.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.5.3.tgz", + "integrity": "sha512-zdpnnKU+H6mOp7nYRXH4GNv1ux6HL6+lHL8g7Ds7Lj8CkdK1jJK/dlwsKDculbyOHifcJ0Pr/yeXnZQ5GeFrcg==", "dev": true, "requires": { "accepts": "~1.3.4", @@ -20670,14 +20661,6 @@ "dev": true, "requires": { "safe-buffer": "~5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true - } } }, "string-width": { @@ -21039,9 +21022,9 @@ "dev": true }, "ua-parser-js": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.31.tgz", - "integrity": "sha512-qLK/Xe9E2uzmYI3qLeOmI0tEOt+TBBQyUIAh4aAgU05FVYzeZrKUdkAZfBNVGRaHVgV0TDkdEngJSw/SyQchkQ==", + "version": "0.7.32", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.32.tgz", + "integrity": "sha512-f9BESNVhzlhEFf2CHMSj40NWOjYPl1YKYbrvIr/hFTDEmLq7SRbWvm7FcdcpCYT95zrOhC7gZSxjdnnTpBcwVw==", "dev": true }, "unicode-canonical-property-names-ecmascript": { @@ -21486,9 +21469,9 @@ "dev": true }, "ws": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", "requires": {} }, "xmlhttprequest-ssl": { diff --git a/kdb-web/src/app/app.component.ts b/kdb-web/src/app/app.component.ts index 72139e6689..1a2cf35ff9 100644 --- a/kdb-web/src/app/app.component.ts +++ b/kdb-web/src/app/app.component.ts @@ -1,4 +1,6 @@ import { Component, OnInit } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { PrimeNGConfig } from 'primeng/api'; import { AuthService } from './services/auth/auth.service'; import { SocketService } from './services/socket/socket.service'; import { ThemeService } from './services/theme/theme.service'; @@ -18,10 +20,10 @@ export class AppComponent implements OnInit { constructor( private authService: AuthService, private themeService: ThemeService, - private socket: SocketService - ) { } - - ngOnInit(): void { + private socket: SocketService, + private translateService: TranslateService, + private config: PrimeNGConfig + ) { this.themeService.sidebarWidth$.subscribe(value => { this.sidebarWidth = value; }); @@ -31,11 +33,33 @@ export class AppComponent implements OnInit { this.authService.isLoggedIn$.subscribe(value => { this.isLoggedIn = value; }); + } + + ngOnInit(): void { + this.translateService.setDefaultLang('en'); this.themeService.loadTheme(); this.socket.startSocket(); } + loadLang(): void { + let lang = localStorage.getItem(`default_lang`); + if (!lang) { + lang = 'en'; + this.setLang(lang); + } + this.translate(lang); + } + + setLang(lang: string): void { + localStorage.setItem(`default_lang`, lang); + } + + translate(lang: string) { + this.translateService.use(lang); + this.translateService.get('primeng').subscribe(res => this.config.setTranslation(res)); + } + setSideWidth($event: any): void { this.themeService.setSideWidth($event); diff --git a/kdb-web/src/app/components/header/header.component.ts b/kdb-web/src/app/components/header/header.component.ts index ff71d92fca..441ceb585e 100644 --- a/kdb-web/src/app/components/header/header.component.ts +++ b/kdb-web/src/app/components/header/header.component.ts @@ -29,7 +29,6 @@ export class HeaderComponent implements OnInit { ) { } ngOnInit(): void { - this.translateService.setDefaultLang('en'); this.initMenuLists(); this.loadLang(); this.translateService.onLangChange.subscribe((event: LangChangeEvent) => { diff --git a/kdb-web/src/app/modules/auth/auth.module.ts b/kdb-web/src/app/modules/auth/auth.module.ts index 4e7c48c3a7..e0afca6a74 100644 --- a/kdb-web/src/app/modules/auth/auth.module.ts +++ b/kdb-web/src/app/modules/auth/auth.module.ts @@ -1,18 +1,20 @@ -import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { SharedModule } from '../shared/shared.module'; import { AuthRoutingModule } from './auth-routing.module'; +import { AuthHeaderComponent } from './components/auth-header/auth-header.component'; import { ForgetPasswordComponent } from './components/forget-password/forget-password.component'; import { LoginComponent } from './components/login/login.component'; import { RegistrationComponent } from './components/registration/registration.component'; -import { SharedModule } from '../shared/shared.module'; @NgModule({ declarations: [ ForgetPasswordComponent, LoginComponent, - RegistrationComponent + RegistrationComponent, + AuthHeaderComponent ], imports: [ CommonModule, diff --git a/kdb-web/src/app/modules/auth/components/auth-header/auth-header.component.html b/kdb-web/src/app/modules/auth/components/auth-header/auth-header.component.html new file mode 100644 index 0000000000..1b48c14749 --- /dev/null +++ b/kdb-web/src/app/modules/auth/components/auth-header/auth-header.component.html @@ -0,0 +1,10 @@ +
+
+ + +
+
+ + +
+
\ No newline at end of file diff --git a/kdb-web/src/app/modules/auth/components/auth-header/auth-header.component.scss b/kdb-web/src/app/modules/auth/components/auth-header/auth-header.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/kdb-web/src/app/modules/auth/components/auth-header/auth-header.component.spec.ts b/kdb-web/src/app/modules/auth/components/auth-header/auth-header.component.spec.ts new file mode 100644 index 0000000000..7afe71ab2c --- /dev/null +++ b/kdb-web/src/app/modules/auth/components/auth-header/auth-header.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AuthHeaderComponent } from './auth-header.component'; + +describe('AuthHeaderComponent', () => { + let component: AuthHeaderComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ AuthHeaderComponent ] + }) + .compileComponents(); + + fixture = TestBed.createComponent(AuthHeaderComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/kdb-web/src/app/modules/auth/components/auth-header/auth-header.component.ts b/kdb-web/src/app/modules/auth/components/auth-header/auth-header.component.ts new file mode 100644 index 0000000000..0858dc8aab --- /dev/null +++ b/kdb-web/src/app/modules/auth/components/auth-header/auth-header.component.ts @@ -0,0 +1,83 @@ +import { Component, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { TranslateService, LangChangeEvent } from '@ngx-translate/core'; +import { MenuItem, PrimeNGConfig } from 'primeng/api'; +import { catchError } from 'rxjs'; +import { AuthService } from 'src/app/services/auth/auth.service'; +import { SettingsService } from 'src/app/services/settings/settings.service'; +import { SpinnerService } from 'src/app/services/spinner/spinner.service'; +import { ThemeService } from 'src/app/services/theme/theme.service'; + +@Component({ + selector: 'app-auth-header', + templateUrl: './auth-header.component.html', + styleUrls: ['./auth-header.component.scss'] +}) +export class AuthHeaderComponent implements OnInit { + langList: MenuItem[] = []; + themeList: MenuItem[] = []; + userMenuList!: MenuItem[]; + + constructor( + private router: Router, + private themeService: ThemeService, + private spinnerService: SpinnerService, + private settings: SettingsService, + private translateService: TranslateService, + private config: PrimeNGConfig + ) { } + + ngOnInit(): void { + this.initMenuLists(); + this.loadLang(); + } + + initMenuLists(): void { + this.langList = [ + { + label: 'English', command: () => { + this.translate('en'); + this.setLang('en'); + }, + }, + { + label: 'Deutsch', command: () => { + this.translate('de'); + this.setLang('de'); + }, + }, + ]; + + this.settings.getThemes()?.forEach(theme => { + this.themeList.push({ + label: theme.Label, + command: () => { + this.changeTheme(theme.Name); + } + }); + }); + } + + changeTheme(name: string): void { + this.themeService.setTheme(name, true); + } + + translate(lang: string) { + this.translateService.use(lang); + this.translateService.get('primeng').subscribe(res => this.config.setTranslation(res)); + } + + loadLang(): void { + let lang = localStorage.getItem(`default_lang`); + if (!lang) { + lang = 'en'; + this.setLang(lang); + } + this.translate(lang); + } + + setLang(lang: string): void { + localStorage.setItem(`default_lang`, lang); + } + +} diff --git a/kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.html b/kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.html index e1fee63eab..71f7761e6d 100644 --- a/kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.html +++ b/kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.html @@ -5,24 +5,26 @@

{{'auth.header' | translate}}

- +
{{'auth.forgot_password.send_confirmation_url' | translate}}
@@ -33,8 +35,8 @@

{{'auth.header' | translate}}

- +
@@ -42,16 +44,20 @@ placeholder="{{'auth.forgot_password.repeat_password' | translate}}" [ngClass]="{ 'invalid-feedback-input': submitted && repeatErrors.password}">
-
{{'auth.forgot_password.passwords_do_not_match' | translate}}
+
{{'auth.forgot_password.passwords_do_not_match' | + translate}}
+ +
\ No newline at end of file diff --git a/kdb-web/src/app/modules/auth/components/login/login.component.html b/kdb-web/src/app/modules/auth/components/login/login.component.html index 43ea33cdde..54789beefb 100644 --- a/kdb-web/src/app/modules/auth/components/login/login.component.html +++ b/kdb-web/src/app/modules/auth/components/login/login.component.html @@ -4,7 +4,7 @@

sh-edraft.de

-
- E-Mail wird benötigt
-
Benutzer nicht gefunden
-
E-Mail wurde nicht bestätigt
+ {{'auth.login.e_mail_required' | translate}}
+
{{'auth.login.user_not_found' | translate}}
+
{{'auth.login.e_mail_not_confirmed' | translate}}
@@ -24,7 +24,7 @@ styleClass="p-password p-component p-inputwrapper p-input-icon-right" Remove after update! --> -
- Password wird benötigt
-
Falsches passwort
+ {{'auth.login.password_required' | translate}}
+
{{'auth.login.wrong_password' | translate}}
+ + \ No newline at end of file diff --git a/kdb-web/src/app/modules/auth/components/registration/registration.component.html b/kdb-web/src/app/modules/auth/components/registration/registration.component.html index 2d9f41bdc5..ba7eac00c4 100644 --- a/kdb-web/src/app/modules/auth/components/registration/registration.component.html +++ b/kdb-web/src/app/modules/auth/components/registration/registration.component.html @@ -4,80 +4,82 @@

sh-edraft.de

-
- Vorname wird benötigt
-
Vorname ist ungültig
+ {{'auth.register.first_name_required' | translate}}
+
{{'auth.register.first_name_invalid' | translate}}
-
- Nachname wird benötigt
-
Nachname ist ungültig
+ {{'auth.register.last_name_required' | translate}}
+
{{'auth.register.last_name_invalid' | translate}}
-
- E-Mail wird benötigt
-
Benutzer existiert bereits
+ {{'auth.register.e_mail_required' | translate}}
+
{{'auth.register.user_already_exists' | translate}}
-
-
Die E-Mails stimmen nicht überein
+
{{'auth.register.e_mails_not_match' | translate}}
-
- Password wird benötigt
+ {{'auth.register.password_required' | translate}}
-
-
Die Passwörter stimmen nicht überein
+
{{'auth.register.passwords_not_match' | translate}}
+ + \ No newline at end of file diff --git a/kdb-web/src/app/services/theme/theme.service.ts b/kdb-web/src/app/services/theme/theme.service.ts index 6dc3410ab2..6abe0955e2 100644 --- a/kdb-web/src/app/services/theme/theme.service.ts +++ b/kdb-web/src/app/services/theme/theme.service.ts @@ -41,7 +41,7 @@ export class ThemeService { const mail = this.authService.getEMailFromDecodedToken(token); let defaultThemeName = localStorage.getItem(`default_themeName`); - if (!defaultThemeName || defaultThemeName != Themes.Default) { + if (!defaultThemeName) { defaultThemeName = Themes.Default; } @@ -58,7 +58,13 @@ export class ThemeService { this.setTheme(userThemeName); } - setTheme(name: string): void { + setTheme(name: string, isDefault: boolean = false): void { + if (isDefault) { + localStorage.setItem(`default_themeName`, name); + this.themeName$.next(name); + return; + } + this.authService.isUserLoggedInAsync().then(result => { if (!result) { localStorage.setItem(`default_themeName`, Themes.Default); diff --git a/kdb-web/src/assets/i18n/de.json b/kdb-web/src/assets/i18n/de.json index 9eec0bf3a4..9f305603c9 100644 --- a/kdb-web/src/assets/i18n/de.json +++ b/kdb-web/src/assets/i18n/de.json @@ -89,8 +89,37 @@ }, "auth": { "header": "Krümmelmonster WI", - "login": {}, - "register": {}, + "login": { + "e_mail": "E-Mail", + "password": "Passwort", + "login": "Einloggen", + "register": "Registrieren", + "forgot_password": "Passwort vergessen?", + "e_mail_required": "E-Mail benötigt", + "user_not_found": "Benutzer nicht gefunden", + "e_mail_not_confirmed": "E-Mail nicht bestätigt", + "password_required": "Passwort benötigt", + "wrong_password": "Falsches passwort" + }, + "register": { + "first_name": "Vorname", + "last_name": "Nachname", + "e_mail": "E-Mail", + "repeat_e_mail": "E-mail wiederholen", + "password": "Password", + "repeat_password": "password wiederholen", + "register": "Registrieren", + "login": "Einloggen", + "user_already_exists": "Benutzer existiert bereits", + "passwords_not_match": "Passwörter sitmmen nicht überein", + "e_mails_not_match": "E-Mails sitmmen nicht überein", + "first_name_required": "Vorname benötigt", + "last_name_required": "Nachname benötigt", + "e_mail_required": "E-Mail benötigt", + "password_required": "Passwort benötigt", + "first_name_invalid": "Vorname ungültig", + "last_name_invalid": "Nachname ungültig" + }, "forgot_password": { "e_mail": "E-Mail", "send_confirmation_url": "Falls ein Benutzer mit der E-Mail gefunden wurde, wurde Betstätigungslink versendet", diff --git a/kdb-web/src/assets/i18n/en.json b/kdb-web/src/assets/i18n/en.json index d289c560e2..0851c3e422 100644 --- a/kdb-web/src/assets/i18n/en.json +++ b/kdb-web/src/assets/i18n/en.json @@ -92,7 +92,7 @@ "password": "Password", "login": "Login", "register": "Register", - "forgot_password": "Forgot password", + "forgot_password": "Forgot password?", "e_mail_required": "E-Mail required", "user_not_found": "User not found", "e_mail_not_confirmed": "Email was not confirmed", @@ -114,7 +114,7 @@ "first_name_required": "Forename required", "last_name_required": "Surname required", "e_mail_required": "E-Mail required", - "password_required": "Passwort required", + "password_required": "Password required", "first_name_invalid": "Forename invalid", "last_name_invalid": "Surname invalid" }, diff --git a/kdb-web/src/styles.scss b/kdb-web/src/styles.scss index 8bbd6cd8a5..58c341153a 100644 --- a/kdb-web/src/styles.scss +++ b/kdb-web/src/styles.scss @@ -68,6 +68,12 @@ header { } } +.auth-header { + .p-menu-overlay { + width: 180px !important; + } +} + .app { height: 100%; display: flex; @@ -361,8 +367,11 @@ footer { display: flex; justify-content: center; align-items: center; + flex-direction: column; + gap: 15px; - .login-form-wrapper { + .login-form-wrapper, + .auth-header { width: 350px; height: 350px; @@ -418,6 +427,11 @@ footer { .register-confirm-form-wrapper { height: 250px; } + + .auth-header { + width: 350px; + height: 75px; + } } .input-field { diff --git a/kdb-web/src/styles/primeng-fixes.scss b/kdb-web/src/styles/primeng-fixes.scss index 5bad03ee8e..c6b246f494 100644 --- a/kdb-web/src/styles/primeng-fixes.scss +++ b/kdb-web/src/styles/primeng-fixes.scss @@ -23,8 +23,11 @@ } } -.p-menu-overlay { - top: $headerHeight !important; +header, +.app { + .p-menu-overlay { + top: $headerHeight !important; + } } .p-panelmenu { diff --git a/kdb-web/src/styles/themes/default-dark-theme.scss b/kdb-web/src/styles/themes/default-dark-theme.scss index 8a5b60fae4..9f0e2f6e45 100644 --- a/kdb-web/src/styles/themes/default-dark-theme.scss +++ b/kdb-web/src/styles/themes/default-dark-theme.scss @@ -194,7 +194,8 @@ .login-wrapper { background-color: $secondaryBackgroundColor; - .login-form-wrapper { + .login-form-wrapper, + .auth-header { background-color: $primaryBackgroundColor; .login-form { @@ -424,7 +425,7 @@ } input, - .p-password { + .p-password input { border-radius: 10px; border: $default-border; diff --git a/kdb-web/src/styles/themes/default-light-theme.scss b/kdb-web/src/styles/themes/default-light-theme.scss index bc58a6f7a0..69a1b97d44 100644 --- a/kdb-web/src/styles/themes/default-light-theme.scss +++ b/kdb-web/src/styles/themes/default-light-theme.scss @@ -194,7 +194,8 @@ .login-wrapper { background-color: $secondaryBackgroundColor; - .login-form-wrapper { + .login-form-wrapper, + .auth-header { background-color: $primaryBackgroundColor; .login-form { @@ -424,7 +425,7 @@ } input, - .p-password { + .p-password input { border-radius: 10px; border: $default-border; diff --git a/kdb-web/src/styles/themes/sh-edraft-dark-theme.scss b/kdb-web/src/styles/themes/sh-edraft-dark-theme.scss index 9e45019f04..cef76707aa 100644 --- a/kdb-web/src/styles/themes/sh-edraft-dark-theme.scss +++ b/kdb-web/src/styles/themes/sh-edraft-dark-theme.scss @@ -196,7 +196,8 @@ .login-wrapper { background-color: $secondaryBackgroundColor; - .login-form-wrapper { + .login-form-wrapper, + .auth-header { background-color: $primaryBackgroundColor; .login-form { @@ -426,7 +427,7 @@ } input, - .p-password { + .p-password input { border-radius: 10px; border: $default-border; diff --git a/kdb-web/src/styles/themes/sh-edraft-light-theme.scss b/kdb-web/src/styles/themes/sh-edraft-light-theme.scss index 26c70cd5d0..8ae5f72450 100644 --- a/kdb-web/src/styles/themes/sh-edraft-light-theme.scss +++ b/kdb-web/src/styles/themes/sh-edraft-light-theme.scss @@ -194,7 +194,8 @@ .login-wrapper { background-color: $secondaryBackgroundColor; - .login-form-wrapper { + .login-form-wrapper, + .auth-header { background-color: $primaryBackgroundColor; .login-form { @@ -424,7 +425,7 @@ } input, - .p-password { + .p-password input { border-radius: 10px; border: $default-border; From a082b879ca08190715b379ee07962e9ccfedaba2 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Tue, 18 Oct 2022 18:33:03 +0200 Subject: [PATCH 046/102] Secured password handling #70 --- .../src/bot_api/controller/auth_controller.py | 2 +- kdb-bot/src/bot_api/service/auth_service.py | 19 +++++++++++-------- .../transformer/auth_user_transformer.py | 3 ++- .../src/bot_data/migration/api_migration.py | 3 ++- kdb-bot/src/bot_data/model/auth_user.py | 18 ++++++++++++++++-- .../service/auth_user_repository_service.py | 5 +++-- 6 files changed, 35 insertions(+), 15 deletions(-) diff --git a/kdb-bot/src/bot_api/controller/auth_controller.py b/kdb-bot/src/bot_api/controller/auth_controller.py index 78a17e79e6..b74c951855 100644 --- a/kdb-bot/src/bot_api/controller/auth_controller.py +++ b/kdb-bot/src/bot_api/controller/auth_controller.py @@ -56,7 +56,7 @@ class AuthController: return jsonify(result.to_dict()) @Route.get(f'{BasePath}/users/get/') - @Route.authorize(role=AuthRoleEnum.admin) + @Route.authorize async def get_user_from_email(self, email: str) -> Response: result = await self._auth_service.get_auth_user_by_email_async(email) return jsonify(result.to_dict()) diff --git a/kdb-bot/src/bot_api/service/auth_service.py b/kdb-bot/src/bot_api/service/auth_service.py index b2056530d7..5887bb9a30 100644 --- a/kdb-bot/src/bot_api/service/auth_service.py +++ b/kdb-bot/src/bot_api/service/auth_service.py @@ -63,8 +63,8 @@ class AuthService(AuthServiceABC): return mail @staticmethod - def _hash_sha256(password: str) -> str: - return hashlib.sha256(password.encode('utf-8')).hexdigest() + def _hash_sha256(password: str, salt: str) -> str: + return hashlib.sha256(f'{password}{salt}'.encode('utf-8')).hexdigest() @staticmethod def _is_email_valid(email: str) -> bool: @@ -188,8 +188,9 @@ class AuthService(AuthServiceABC): if db_user is not None: raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists') - user_dto.password = self._hash_sha256(user_dto.password) user = AUT.to_db(user_dto) + user.password_salt = uuid.uuid4() + user.password = self._hash_sha256(user_dto.password, user.password_salt) if not self._is_email_valid(user.email): raise ServiceException(ServiceErrorCode.InvalidData, 'Invalid E-Mail address') @@ -244,17 +245,18 @@ class AuthService(AuthServiceABC): # hash passwords in DTOs if update_user_dto.auth_user.password is not None and update_user_dto.auth_user.password != '': is_existing_password_set = True - update_user_dto.auth_user.password = self._hash_sha256(update_user_dto.auth_user.password) + update_user_dto.auth_user.password = self._hash_sha256(update_user_dto.auth_user.password, user.password_salt) if update_user_dto.auth_user.password != user.password: raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong password') if update_user_dto.new_auth_user.password is not None and update_user_dto.new_auth_user.password != '': is_new_password_set = True - update_user_dto.new_auth_user.password = self._hash_sha256(update_user_dto.new_auth_user.password) + update_user_dto.new_auth_user.password = self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt) # update password if is_existing_password_set and is_new_password_set and update_user_dto.auth_user.password != update_user_dto.new_auth_user.password: + user.password_salt = uuid.uuid4() user.password = update_user_dto.new_auth_user.password self._auth_users.update_auth_user(user) @@ -301,7 +303,8 @@ class AuthService(AuthServiceABC): # update password if update_user_dto.change_password and update_user_dto.auth_user.password != update_user_dto.new_auth_user.password: - user.password = self._hash_sha256(update_user_dto.new_auth_user.password) + user.password_salt = uuid.uuid4() + user.password = self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt) # update role if user.auth_role == update_user_dto.auth_user.auth_role and user.auth_role != update_user_dto.new_auth_user.auth_role: @@ -350,7 +353,7 @@ class AuthService(AuthServiceABC): if db_user is None: raise ServiceException(ServiceErrorCode.InvalidUser, f'User not found') - user_dto.password = self._hash_sha256(user_dto.password) + user_dto.password = self._hash_sha256(user_dto.password, db_user.password_salt) if db_user.password != user_dto.password: raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong password') @@ -432,5 +435,5 @@ class AuthService(AuthServiceABC): if user.password is None or rp_dto.password == '': raise ServiceException(ServiceErrorCode.InvalidData, f'Password not set') - user.password = self._hash_sha256(rp_dto.password) + user.password = self._hash_sha256(rp_dto.password, user.password_salt) self._db.save_changes() diff --git a/kdb-bot/src/bot_api/transformer/auth_user_transformer.py b/kdb-bot/src/bot_api/transformer/auth_user_transformer.py index b5608e2376..768cc7ef0f 100644 --- a/kdb-bot/src/bot_api/transformer/auth_user_transformer.py +++ b/kdb-bot/src/bot_api/transformer/auth_user_transformer.py @@ -18,6 +18,7 @@ class AuthUserTransformer(TransformerABC): None, None, None, + None, datetime.now(tz=timezone.utc), AuthRoleEnum.normal if dto.auth_role is None else AuthRoleEnum(dto.auth_role), dto.user_id, @@ -31,7 +32,7 @@ class AuthUserTransformer(TransformerABC): db.first_name, db.last_name, db.email, - db.password, + '', db.confirmation_id, db.auth_role, db.user_id diff --git a/kdb-bot/src/bot_data/migration/api_migration.py b/kdb-bot/src/bot_data/migration/api_migration.py index 6860ae1440..8466ec463b 100644 --- a/kdb-bot/src/bot_data/migration/api_migration.py +++ b/kdb-bot/src/bot_data/migration/api_migration.py @@ -23,12 +23,13 @@ class ApiMigration(MigrationABC): `LastName` VARCHAR(255), `EMail` VARCHAR(255), `Password` VARCHAR(255), + `PasswordSalt` VARCHAR(255), `RefreshToken` VARCHAR(255), `ConfirmationId` VARCHAR(255) DEFAULT NULL, `ForgotPasswordId` VARCHAR(255) DEFAULT NULL, `RefreshTokenExpiryTime` DATETIME(6) NOT NULL, `AuthRole` INT NOT NULL DEFAULT '0', - `UserId` BIGINT NOT NULL DEFAULT '0', + `UserId` BIGINT DEFAULT NULL, `CreatedOn` DATETIME(6) NOT NULL, `LastModifiedOn` DATETIME(6) NOT NULL, PRIMARY KEY(`Id`), diff --git a/kdb-bot/src/bot_data/model/auth_user.py b/kdb-bot/src/bot_data/model/auth_user.py index fe92ad1eb9..58c9f982e5 100644 --- a/kdb-bot/src/bot_data/model/auth_user.py +++ b/kdb-bot/src/bot_data/model/auth_user.py @@ -1,3 +1,4 @@ +import uuid from datetime import datetime from typing import Optional from cpl_core.database import TableABC @@ -14,6 +15,7 @@ class AuthUser(TableABC): last_name: str, email: str, password: str, + password_salt: Optional[str], refresh_token: Optional[str], confirmation_id: Optional[str], forgot_password_id: Optional[str], @@ -29,6 +31,7 @@ class AuthUser(TableABC): self._last_name = last_name self._email = email self._password = password + self._password_salt = uuid.uuid4() if password_salt is None else password_salt self._refresh_token = refresh_token self._confirmation_id = confirmation_id self._forgot_password_id = forgot_password_id @@ -77,6 +80,14 @@ class AuthUser(TableABC): def password(self, value: str): self._password = value + @property + def password_salt(self) -> str: + return self._password_salt + + @password_salt.setter + def password_salt(self, value: str): + self._password_salt = value + @property def refresh_token(self) -> Optional[str]: return self._refresh_token @@ -168,6 +179,7 @@ class AuthUser(TableABC): `LastName`, `EMail`, `Password`, + `PasswordSalt`, `RefreshToken`, `ConfirmationId`, `ForgotPasswordId`, @@ -182,12 +194,13 @@ class AuthUser(TableABC): '{self._last_name}', '{self._email}', '{self._password}', - '{self._refresh_token}', + '{self._password_salt}', + '{"NULL" if self._refresh_token is None else self._refresh_token}', '{"NULL" if self._confirmation_id is None else self._confirmation_id}', '{"NULL" if self._forgot_password_id is None else self._forgot_password_id}', '{self._refresh_token_expire_time}', {self._auth_role_id.value}, - {"NULL" if self._user_id is None else self._user_id} + {"NULL" if self._user_id is None else self._user_id}, '{self._created_at}', '{self._modified_at}' ) @@ -201,6 +214,7 @@ class AuthUser(TableABC): `LastName` = '{self._last_name}', `EMail` = '{self._email}', `Password` = '{self._password}', + `PasswordSalt` = '{self._password_salt}', `RefreshToken` = '{self._refresh_token}', `ConfirmationId` = '{"NULL" if self._confirmation_id is None else self._confirmation_id}', `ForgotPasswordId` = '{"NULL" if self._forgot_password_id is None else self._forgot_password_id}', diff --git a/kdb-bot/src/bot_data/service/auth_user_repository_service.py b/kdb-bot/src/bot_data/service/auth_user_repository_service.py index c8fee7b4aa..ce8e3e4bd7 100644 --- a/kdb-bot/src/bot_data/service/auth_user_repository_service.py +++ b/kdb-bot/src/bot_data/service/auth_user_repository_service.py @@ -36,8 +36,9 @@ class AuthUserRepositoryService(AuthUserRepositoryABC): self._get_value_from_result(result[6]), self._get_value_from_result(result[7]), self._get_value_from_result(result[8]), - AuthRoleEnum(self._get_value_from_result(result[9])), - self._get_value_from_result(result[10]), + self._get_value_from_result(result[9]), + AuthRoleEnum(self._get_value_from_result(result[10])), + self._get_value_from_result(result[11]), id=self._get_value_from_result(result[0]) ) From 47a73a42981fe198bdce951d8af8ed039f0d2e08 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Tue, 18 Oct 2022 19:50:13 +0200 Subject: [PATCH 047/102] Fixed password handling #70 --- .../src/bot_api/controller/auth_controller.py | 11 +++++++-- .../src/bot_api/model/update_auth_user_dto.py | 4 ++-- kdb-bot/src/bot_api/service/auth_service.py | 23 +++++++------------ 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/kdb-bot/src/bot_api/controller/auth_controller.py b/kdb-bot/src/bot_api/controller/auth_controller.py index b74c951855..2d03b37a3d 100644 --- a/kdb-bot/src/bot_api/controller/auth_controller.py +++ b/kdb-bot/src/bot_api/controller/auth_controller.py @@ -12,6 +12,7 @@ from bot_api.filter.auth_user_select_criteria import AuthUserSelectCriteria from bot_api.json_processor import JSONProcessor from bot_api.logging.api_logger import ApiLogger from bot_api.model.auth_user_dto import AuthUserDTO +from bot_api.model.reset_password_dto import ResetPasswordDTO from bot_api.model.token_dto import TokenDTO from bot_api.model.update_auth_user_dto import UpdateAuthUserDTO from bot_api.route.route import Route @@ -62,7 +63,7 @@ class AuthController: return jsonify(result.to_dict()) @Route.get(f'{BasePath}/users/find/') - @Route.authorize(role=AuthRoleEnum.admin) + @Route.authorize async def find_user_from_email(self, email: str) -> Response: result = await self._auth_service.find_auth_user_by_email_async(email) return jsonify(result.to_dict()) @@ -99,7 +100,13 @@ class AuthController: @Route.post(f'{BasePath}/confirm-forgot-password/') async def confirm_forgot_password(self, id: str): - await self._auth_service.confirm_forgot_password_async(id) + result = await self._auth_service.confirm_forgot_password_async(id) + return jsonify(result.to_dict()) + + @Route.post(f'{BasePath}/reset-password') + async def reset_password(self): + dto: ResetPasswordDTO = JSONProcessor.process(ResetPasswordDTO, request.get_json(force=True, silent=True)) + await self._auth_service.reset_password_async(dto) return '', 200 @Route.post(f'{BasePath}/update-user') diff --git a/kdb-bot/src/bot_api/model/update_auth_user_dto.py b/kdb-bot/src/bot_api/model/update_auth_user_dto.py index 9caa94738c..254c0c727c 100644 --- a/kdb-bot/src/bot_api/model/update_auth_user_dto.py +++ b/kdb-bot/src/bot_api/model/update_auth_user_dto.py @@ -12,7 +12,7 @@ class UpdateAuthUserDTO(DtoABC): self, auth_user_dto: AuthUserDTO, new_auth_user_dto: AuthUserDTO, - change_password=False + change_password: bool = False ): DtoABC.__init__(self) @@ -35,7 +35,7 @@ class UpdateAuthUserDTO(DtoABC): def from_dict(self, values: dict): self._auth_user = values['authUser'] self._new_auth_user = values['newAuthUser'] - self._change_password = False if 'changePassword' not in values else values['changePassword'] + self._change_password = False if 'changePassword' not in values else bool(values['changePassword']) def to_dict(self) -> dict: return { diff --git a/kdb-bot/src/bot_api/service/auth_service.py b/kdb-bot/src/bot_api/service/auth_service.py index 5887bb9a30..3057cd84ea 100644 --- a/kdb-bot/src/bot_api/service/auth_service.py +++ b/kdb-bot/src/bot_api/service/auth_service.py @@ -240,24 +240,14 @@ class AuthService(AuthServiceABC): raise ServiceException(ServiceErrorCode.InvalidUser, 'User already exists') user.email = update_user_dto.new_auth_user.email - is_existing_password_set = False - is_new_password_set = False - # hash passwords in DTOs - if update_user_dto.auth_user.password is not None and update_user_dto.auth_user.password != '': - is_existing_password_set = True - update_user_dto.auth_user.password = self._hash_sha256(update_user_dto.auth_user.password, user.password_salt) - + update_user_dto.auth_user.password = self._hash_sha256(update_user_dto.auth_user.password, user.password_salt) if update_user_dto.auth_user.password != user.password: raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong password') - if update_user_dto.new_auth_user.password is not None and update_user_dto.new_auth_user.password != '': - is_new_password_set = True - update_user_dto.new_auth_user.password = self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt) - # update password - if is_existing_password_set and is_new_password_set and update_user_dto.auth_user.password != update_user_dto.new_auth_user.password: + if self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt) != user.password: user.password_salt = uuid.uuid4() - user.password = update_user_dto.new_auth_user.password + user.password = self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt) self._auth_users.update_auth_user(user) self._db.save_changes() @@ -302,7 +292,7 @@ class AuthService(AuthServiceABC): user.email = update_user_dto.new_auth_user.email # update password - if update_user_dto.change_password and update_user_dto.auth_user.password != update_user_dto.new_auth_user.password: + if update_user_dto.change_password and user.password != self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt): user.password_salt = uuid.uuid4() user.password = self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt) @@ -340,7 +330,7 @@ class AuthService(AuthServiceABC): if user is None: raise ServiceException(ServiceErrorCode.InvalidData, 'Token expired') except Exception as e: - self._logger.error(__name__, f'Refreshing token failed', e) + self._logger.error(__name__, f'Token invalid', e) return False return True @@ -435,5 +425,8 @@ class AuthService(AuthServiceABC): if user.password is None or rp_dto.password == '': raise ServiceException(ServiceErrorCode.InvalidData, f'Password not set') + user.password_salt = uuid.uuid4() user.password = self._hash_sha256(rp_dto.password, user.password_salt) + user.forgot_password_id = None + self._auth_users.update_auth_user(user) self._db.save_changes() From d0ded956cb3fa5c75eb156a7699470ed1e00e175 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Tue, 18 Oct 2022 21:00:13 +0200 Subject: [PATCH 048/102] [WIP] Fixed forgot password #70 --- kdb-bot/src/bot/bot.json | 4 +-- kdb-bot/src/bot_api/service/auth_service.py | 27 ++++++++++--------- .../forget-password.component.ts | 1 + .../components/login/login.component.html | 2 +- kdb-web/src/app/services/auth/auth.service.ts | 6 ++--- kdb-web/src/styles.scss | 10 +++---- 6 files changed, 26 insertions(+), 24 deletions(-) diff --git a/kdb-bot/src/bot/bot.json b/kdb-bot/src/bot/bot.json index 985c978b2c..f7fdb2cfc5 100644 --- a/kdb-bot/src/bot/bot.json +++ b/kdb-bot/src/bot/bot.json @@ -16,10 +16,10 @@ "LicenseName": "MIT", "LicenseDescription": "MIT, see LICENSE for more details.", "Dependencies": [ - "cpl-core==2022.10.0.post6", + "cpl-core==2022.10.0.post7", "cpl-translation==2022.10.0.post1", "cpl-query==2022.10.0.post2", - "cpl-discord==2022.10.0.post5", + "cpl-discord==2022.10.0.post6", "Flask==2.2.2", "Flask-Classful==0.14.2", "Flask-Cors==3.0.10", diff --git a/kdb-bot/src/bot_api/service/auth_service.py b/kdb-bot/src/bot_api/service/auth_service.py index 3057cd84ea..15fa8138cc 100644 --- a/kdb-bot/src/bot_api/service/auth_service.py +++ b/kdb-bot/src/bot_api/service/auth_service.py @@ -6,6 +6,7 @@ from typing import Optional import jwt from cpl_core.database.context import DatabaseContextABC +from cpl_core.environment import ApplicationEnvironmentABC from cpl_core.mailing import EMailClientABC, EMail from cpl_query.extension import List from cpl_translation import TranslatePipe @@ -35,6 +36,7 @@ class AuthService(AuthServiceABC): def __init__( self, + env: ApplicationEnvironmentABC, logger: ApiLogger, auth_users: AuthUserRepositoryABC, db: DatabaseContextABC, @@ -46,6 +48,7 @@ class AuthService(AuthServiceABC): ): AuthServiceABC.__init__(self) + self._environment = env self._logger = logger self._auth_users = auth_users self._db = db @@ -54,14 +57,6 @@ class AuthService(AuthServiceABC): self._auth_settings = auth_settings self._frontend_settings = frontend_settings - @staticmethod - def _get_mail_to_send() -> EMail: - mail = EMail() - mail.add_header('Mime-Version: 1.0') - mail.add_header('Content-Type: text/plain charset=utf-8') - mail.add_header('Content-Transfer-Encoding: quoted-printable') - return mail - @staticmethod def _hash_sha256(password: str, salt: str) -> str: return hashlib.sha256(f'{password}{salt}'.encode('utf-8')).hexdigest() @@ -141,10 +136,14 @@ class AuthService(AuthServiceABC): if not url.endswith('/'): url = f'{url}/' - mail = self._get_mail_to_send() + mail = EMail() + mail.add_header('Mime-Version: 1.0') + mail.add_header('Content-Type: text/plain charset=utf-8') + mail.add_header('Content-Transfer-Encoding: quoted-printable') mail.add_receiver(user.email) mail.subject = self._t.transform('api.auth.confirmation.subject').format(user.first_name, user.last_name) mail.body = self._t.transform('api.auth.confirmation.message').format(url, user.confirmation_id) + mail.body += f'\n\nDies ist eine automatische E-Mail.\nGesendet von {self._environment.application_name}-{self._environment.environment_name}@{self._environment.host_name}' self._mailer.send_mail(mail) def _send_forgot_password_id_to_user(self, user: AuthUser): @@ -152,10 +151,14 @@ class AuthService(AuthServiceABC): if not url.endswith('/'): url = f'{url}/' - mail = self._get_mail_to_send() + mail = EMail() + mail.add_header('Mime-Version: 1.0') + mail.add_header('Content-Type: text/plain charset=utf-8') + mail.add_header('Content-Transfer-Encoding: quoted-printable') mail.add_receiver(user.email) - mail.subject = self._t.transform('api.auth.forgot_password.subject').format(user.first_name, user.last_name) - mail.body = self._t.transform('api.auth.forgot_password.message').format(url, user.forgot_password_id) + mail.subject = str(self._t.transform('api.auth.forgot_password.subject').format(user.first_name, user.last_name)) + mail.body = str(self._t.transform('api.auth.forgot_password.message').format(url, user.forgot_password_id)) + mail.body += f'\n\nDies ist eine automatische E-Mail.\nGesendet von {self._environment.application_name}-{self._environment.environment_name}@{self._environment.host_name}' self._mailer.send_mail(mail) async def get_all_auth_users_async(self) -> List[AuthUserDTO]: diff --git a/kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.ts b/kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.ts index c49c6be16f..f73bd20e97 100644 --- a/kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.ts +++ b/kdb-web/src/app/modules/auth/components/forget-password/forget-password.component.ts @@ -37,6 +37,7 @@ export class ForgetPasswordComponent implements OnInit { ) { } ngOnInit(): void { + console.log('test'); this.spinnerService.showSpinner(); this.authService.isUserLoggedInAsync().then(result => { if (result) { diff --git a/kdb-web/src/app/modules/auth/components/login/login.component.html b/kdb-web/src/app/modules/auth/components/login/login.component.html index 54789beefb..d6ee032619 100644 --- a/kdb-web/src/app/modules/auth/components/login/login.component.html +++ b/kdb-web/src/app/modules/auth/components/login/login.component.html @@ -2,7 +2,7 @@ - \ No newline at end of file + From 1f2087f50f9720beeaabe381b6fd25ba33aaf54a Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Tue, 25 Oct 2022 21:11:55 +0200 Subject: [PATCH 094/102] Fixed update user #85 --- kdb-bot/src/bot_api/service/auth_service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kdb-bot/src/bot_api/service/auth_service.py b/kdb-bot/src/bot_api/service/auth_service.py index 4c9fcaf190..bf5d9f86c1 100644 --- a/kdb-bot/src/bot_api/service/auth_service.py +++ b/kdb-bot/src/bot_api/service/auth_service.py @@ -349,7 +349,7 @@ class AuthService(AuthServiceABC): raise ServiceException(ServiceErrorCode.InvalidUser, 'Wrong password') # update password - if self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt) != user.password: + if update_user_dto.new_auth_user.password is not None and self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt) != user.password: user.password_salt = uuid.uuid4() user.password = self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt) From ac5271de6d7b7a45bbc3d82d2c465ae2ee8dbb10 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Tue, 25 Oct 2022 21:15:40 +0200 Subject: [PATCH 095/102] Fixed update user #85 --- kdb-bot/src/bot_api/service/auth_service.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kdb-bot/src/bot_api/service/auth_service.py b/kdb-bot/src/bot_api/service/auth_service.py index bf5d9f86c1..ba45a15531 100644 --- a/kdb-bot/src/bot_api/service/auth_service.py +++ b/kdb-bot/src/bot_api/service/auth_service.py @@ -396,7 +396,7 @@ class AuthService(AuthServiceABC): user.email = update_user_dto.new_auth_user.email # update password - if update_user_dto.change_password and user.password != self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt): + if update_user_dto.new_auth_user.password is not None and update_user_dto.change_password and user.password != self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt): user.password_salt = uuid.uuid4() user.password = self._hash_sha256(update_user_dto.new_auth_user.password, user.password_salt) From 8e32362333dc1fb4b59d0a9ba716e6dc25309ab9 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 5 Nov 2022 11:51:58 +0100 Subject: [PATCH 096/102] Changed config #70 --- ...ettings.edrafts-pc-ubuntu.json => apisettings.edrafts-pc.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename kdb-bot/src/bot_api/config/{apisettings.edrafts-pc-ubuntu.json => apisettings.edrafts-pc.json} (100%) diff --git a/kdb-bot/src/bot_api/config/apisettings.edrafts-pc-ubuntu.json b/kdb-bot/src/bot_api/config/apisettings.edrafts-pc.json similarity index 100% rename from kdb-bot/src/bot_api/config/apisettings.edrafts-pc-ubuntu.json rename to kdb-bot/src/bot_api/config/apisettings.edrafts-pc.json From e45d156e74740ad7317f5a19fa0c626e74f897c3 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 5 Nov 2022 11:52:31 +0100 Subject: [PATCH 097/102] Changed config #70 --- ...ettings.edrafts-pc-ubuntu.json => appsettings.edrafts-pc.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename kdb-bot/src/bot/config/{appsettings.edrafts-pc-ubuntu.json => appsettings.edrafts-pc.json} (100%) diff --git a/kdb-bot/src/bot/config/appsettings.edrafts-pc-ubuntu.json b/kdb-bot/src/bot/config/appsettings.edrafts-pc.json similarity index 100% rename from kdb-bot/src/bot/config/appsettings.edrafts-pc-ubuntu.json rename to kdb-bot/src/bot/config/appsettings.edrafts-pc.json From 422c9bbb253b76b7a1860095c726c729a19d5c94 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 5 Nov 2022 12:03:22 +0100 Subject: [PATCH 098/102] Fixed log level #70 --- kdb-bot/src/bot/config/appsettings.edrafts-pc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kdb-bot/src/bot/config/appsettings.edrafts-pc.json b/kdb-bot/src/bot/config/appsettings.edrafts-pc.json index 9deca01737..2e9e52a3d7 100644 --- a/kdb-bot/src/bot/config/appsettings.edrafts-pc.json +++ b/kdb-bot/src/bot/config/appsettings.edrafts-pc.json @@ -8,7 +8,7 @@ "LoggingSettings": { "Path": "logs/", "Filename": "bot.log", - "ConsoleLogLevel": "DEBUG", + "ConsoleLogLevel": "TRACE", "FileLogLevel": "TRACE" }, "BotLoggingSettings": { From c92403f27481a81a77555eba3582c89e9a6cdcd1 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 5 Nov 2022 12:39:49 +0100 Subject: [PATCH 099/102] Removed unused deps #70 --- kdb-bot/src/bot_api/api_thread.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/kdb-bot/src/bot_api/api_thread.py b/kdb-bot/src/bot_api/api_thread.py index f3ecf6cc76..f437d140f2 100644 --- a/kdb-bot/src/bot_api/api_thread.py +++ b/kdb-bot/src/bot_api/api_thread.py @@ -2,8 +2,6 @@ import threading from bot_api.api import Api from bot_api.logging.api_logger import ApiLogger -from bot_core.configuration.feature_flags_enum import FeatureFlagsEnum -from bot_core.configuration.feature_flags_settings import FeatureFlagsSettings class ApiThread(threading.Thread): @@ -11,8 +9,7 @@ class ApiThread(threading.Thread): def __init__( self, logger: ApiLogger, - api: Api, - feature_flags: FeatureFlagsSettings + api: Api ): threading.Thread.__init__(self, daemon=True) From 09a6062992a9f027c1956777f20a183a59b6b8a1 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 5 Nov 2022 12:40:21 +0100 Subject: [PATCH 100/102] Fixed typing #70 --- kdb-bot/src/bot_api/model/discord/server_dto.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kdb-bot/src/bot_api/model/discord/server_dto.py b/kdb-bot/src/bot_api/model/discord/server_dto.py index 07cd4365c4..a4a5a2da95 100644 --- a/kdb-bot/src/bot_api/model/discord/server_dto.py +++ b/kdb-bot/src/bot_api/model/discord/server_dto.py @@ -46,7 +46,7 @@ class ServerDTO(DtoABC): self._server_id = int(values['serverId']) self._discord_id = int(values['discordId']) self._name = values['name'] - self._icon_url = int(values['iconURL']) + self._icon_url = values['iconURL'] def to_dict(self) -> dict: return { From 88f00c604694571465d9b35376d78a9ae9440abc Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 5 Nov 2022 12:42:22 +0100 Subject: [PATCH 101/102] Fixed typing #70 --- kdb-bot/src/bot_data/migration/api_migration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kdb-bot/src/bot_data/migration/api_migration.py b/kdb-bot/src/bot_data/migration/api_migration.py index 53df1192e1..8f59906a6f 100644 --- a/kdb-bot/src/bot_data/migration/api_migration.py +++ b/kdb-bot/src/bot_data/migration/api_migration.py @@ -29,7 +29,7 @@ class ApiMigration(MigrationABC): `ForgotPasswordId` VARCHAR(255) DEFAULT NULL, `OAuthId` VARCHAR(255) DEFAULT NULL, `RefreshTokenExpiryTime` DATETIME(6) NOT NULL, - `AuthRole` INT NOT NULL DEFAULT '0', + `AuthRole` INT NOT NULL DEFAULT 0, `CreatedAt` DATETIME(6) NOT NULL, `LastModifiedAt` DATETIME(6) NOT NULL, PRIMARY KEY(`Id`) From e1304cc6023eb152f2a5201281553cbafd946321 Mon Sep 17 00:00:00 2001 From: Sven Heidemann Date: Sat, 5 Nov 2022 13:49:01 +0100 Subject: [PATCH 102/102] Added comment #70 --- kdb-bot/src/bot_api/service/auth_service.py | 1 + 1 file changed, 1 insertion(+) diff --git a/kdb-bot/src/bot_api/service/auth_service.py b/kdb-bot/src/bot_api/service/auth_service.py index ba45a15531..be0859db20 100644 --- a/kdb-bot/src/bot_api/service/auth_service.py +++ b/kdb-bot/src/bot_api/service/auth_service.py @@ -204,6 +204,7 @@ class AuthService(AuthServiceABC): async def get_auth_user_by_email_async(self, email: str, with_password: bool = False) -> AuthUserDTO: try: + # todo: check if logged in user is admin then send mail user = self._auth_users.get_auth_user_by_email(email) return AUT.to_dto(user, password=user.password if with_password else None) except Exception as e: