diff --git a/alerter/run_alerter.py b/alerter/run_alerter.py index 5240959bd..bb112400c 100644 --- a/alerter/run_alerter.py +++ b/alerter/run_alerter.py @@ -41,7 +41,7 @@ COSMOS_ALERTERS_MANAGER_NAME) from src.utils.constants.rabbitmq import ( ALERT_ROUTER_CONFIGS_QUEUE_NAME, CONFIG_EXCHANGE, - SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME, + SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME, CHANNELS_MANAGER_CONFIGS_QUEUE_NAME, GH_MON_MAN_CONFIGS_QUEUE_NAME, DH_MON_MAN_CONFIGS_QUEUE_NAME, SYS_MON_MAN_CONFIGS_QUEUE_NAME, NODE_MON_MAN_CONFIGS_QUEUE_NAME, EVM_NODES_CONFIGS_ROUTING_KEY_CHAINS, @@ -63,7 +63,8 @@ COSMOS_NODE_ALERTER_INPUT_CONFIGS_QUEUE_NAME, MONITORABLE_STORE_INPUT_QUEUE_NAME, MONITORABLE_EXCHANGE, MONITORABLE_STORE_INPUT_ROUTING_KEY, - COSMOS_NETWORK_ALERTER_INPUT_CONFIGS_QUEUE_NAME) + COSMOS_NETWORK_ALERTER_INPUT_CONFIGS_QUEUE_NAME, + SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME) from src.utils.constants.starters import ( RE_INITIALISE_SLEEPING_PERIOD, RESTART_SLEEPING_PERIOD, ) @@ -922,25 +923,50 @@ def _initialise_and_declare_config_queues() -> None: # System Alerters Manager queues log_and_print("Creating queue '{}'".format( - SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME), dummy_logger) - rabbitmq.queue_declare(SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME, + SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME), dummy_logger) + rabbitmq.queue_declare(SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME, False, True, False, False) log_and_print( "Binding queue '{}' to '{}' exchange with routing " - "key {}.".format(SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME, + "key {}.".format(SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME, CONFIG_EXCHANGE, ALERTS_CONFIGS_ROUTING_KEY_CHAIN), dummy_logger) - rabbitmq.queue_bind(SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME, + rabbitmq.queue_bind(SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME, CONFIG_EXCHANGE, ALERTS_CONFIGS_ROUTING_KEY_CHAIN) log_and_print( "Binding queue '{}' to '{}' exchange with routing " - "key {}.".format(SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME, + "key {}.".format(SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME, CONFIG_EXCHANGE, ALERTS_CONFIGS_ROUTING_KEY_GEN), dummy_logger) - rabbitmq.queue_bind(SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME, + rabbitmq.queue_bind(SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME, + CONFIG_EXCHANGE, + ALERTS_CONFIGS_ROUTING_KEY_GEN) + + # System Alerter queues + log_and_print("Creating queue '{}'".format( + SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME), dummy_logger) + rabbitmq.queue_declare(SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME, + False, True, False, False) + log_and_print( + "Binding queue '{}' to '{}' exchange with routing " + "key {}.".format(SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME, + CONFIG_EXCHANGE, + ALERTS_CONFIGS_ROUTING_KEY_CHAIN), + dummy_logger) + rabbitmq.queue_bind(SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME, + CONFIG_EXCHANGE, + ALERTS_CONFIGS_ROUTING_KEY_CHAIN) + + log_and_print( + "Binding queue '{}' to '{}' exchange with routing " + "key {}.".format(SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME, + CONFIG_EXCHANGE, + ALERTS_CONFIGS_ROUTING_KEY_GEN), + dummy_logger) + rabbitmq.queue_bind(SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME, CONFIG_EXCHANGE, ALERTS_CONFIGS_ROUTING_KEY_GEN) diff --git a/alerter/src/alerter/alert_code/node/chainlink_alert_code.py b/alerter/src/alerter/alert_code/node/chainlink_alert_code.py index d00b2f40d..3112749d6 100644 --- a/alerter/src/alerter/alert_code/node/chainlink_alert_code.py +++ b/alerter/src/alerter/alert_code/node/chainlink_alert_code.py @@ -14,9 +14,9 @@ class ChainlinkNodeAlertCode(AlertCode): NoOfUnconfirmedTxsDecreasedBelowThresholdAlert = 'cl_node_alert_10' TotalErroredJobRunsIncreasedAboveThresholdAlert = 'cl_node_alert_11' TotalErroredJobRunsDecreasedBelowThresholdAlert = 'cl_node_alert_12' - EthBalanceIncreasedAboveThresholdAlert = 'cl_node_alert_13' - EthBalanceDecreasedBelowThresholdAlert = 'cl_node_alert_14' - EthBalanceToppedUpAlert = 'cl_node_alert_15' + BalanceIncreasedAboveThresholdAlert = 'cl_node_alert_13' + BalanceDecreasedBelowThresholdAlert = 'cl_node_alert_14' + BalanceToppedUpAlert = 'cl_node_alert_15' InvalidUrlAlert = 'cl_node_alert_16' ValidUrlAlert = 'cl_node_alert_17' PrometheusSourceIsDownAlert = 'cl_node_alert_18' diff --git a/alerter/src/alerter/alerter_starters.py b/alerter/src/alerter/alerter_starters.py index b0cf5de7c..d9faaf10d 100644 --- a/alerter/src/alerter/alerter_starters.py +++ b/alerter/src/alerter/alerter_starters.py @@ -12,15 +12,15 @@ from src.alerter.alerters.node.cosmos import CosmosNodeAlerter from src.alerter.alerters.node.evm import EVMNodeAlerter from src.alerter.alerters.system import SystemAlerter -from src.configs.alerts.system import SystemAlertsConfig from src.configs.factory.alerts.chainlink_alerts import ( ChainlinkNodeAlertsConfigsFactory, ChainlinkContractAlertsConfigsFactory) from src.configs.factory.alerts.cosmos_alerts import ( CosmosNodeAlertsConfigsFactory, CosmosNetworkAlertsConfigsFactory) from src.configs.factory.alerts.evm_alerts import EVMNodeAlertsConfigsFactory +from src.configs.factory.alerts.system_alerts import SystemAlertsConfigsFactory from src.message_broker.rabbitmq import RabbitMQApi from src.utils.constants.names import ( - SYSTEM_ALERTER_NAME_TEMPLATE, GITHUB_ALERTER_NAME, DOCKERHUB_ALERTER_NAME, + SYSTEM_ALERTER_NAME, GITHUB_ALERTER_NAME, DOCKERHUB_ALERTER_NAME, CHAINLINK_NODE_ALERTER_NAME, CHAINLINK_CONTRACT_ALERTER_NAME, EVM_NODE_ALERTER_NAME, COSMOS_NODE_ALERTER_NAME, COSMOS_NETWORK_ALERTER_NAME) @@ -56,10 +56,11 @@ def _initialise_alerter_logger(alerter_display_name: str, return alerter_logger -def _initialise_system_alerter(system_alerts_config: SystemAlertsConfig, - chain: str) -> SystemAlerter: +def _initialise_system_alerter( + system_alerts_configs_factory: SystemAlertsConfigsFactory +) -> SystemAlerter: # Alerter display name based on system - alerter_display_name = SYSTEM_ALERTER_NAME_TEMPLATE.format(chain) + alerter_display_name = SYSTEM_ALERTER_NAME system_alerter_logger = _initialise_alerter_logger(alerter_display_name, SystemAlerter.__name__) @@ -70,12 +71,11 @@ def _initialise_system_alerter(system_alerts_config: SystemAlertsConfig, rabbitmq = RabbitMQApi( logger=system_alerter_logger.getChild(RabbitMQApi.__name__), host=RABBIT_IP) - system_alerter = SystemAlerter(alerter_display_name, - system_alerts_config, - system_alerter_logger, - rabbitmq, - ALERTER_PUBLISHING_QUEUE_SIZE - ) + system_alerter = SystemAlerter( + alerter_display_name, system_alerter_logger, + system_alerts_configs_factory, rabbitmq, + ALERTER_PUBLISHING_QUEUE_SIZE + ) log_and_print("Successfully initialised {}".format( alerter_display_name), system_alerter_logger) break @@ -100,11 +100,10 @@ def _initialise_github_alerter() -> GithubAlerter: rabbitmq = RabbitMQApi( logger=github_alerter_logger.getChild(RabbitMQApi.__name__), host=RABBIT_IP) - github_alerter = GithubAlerter(alerter_display_name, - github_alerter_logger, - rabbitmq, - ALERTER_PUBLISHING_QUEUE_SIZE - ) + github_alerter = GithubAlerter( + alerter_display_name, github_alerter_logger, rabbitmq, + ALERTER_PUBLISHING_QUEUE_SIZE + ) log_and_print("Successfully initialised {}".format( alerter_display_name), github_alerter_logger) break @@ -129,11 +128,10 @@ def _initialise_dockerhub_alerter() -> DockerhubAlerter: rabbitmq = RabbitMQApi( logger=dockerhub_alerter_logger.getChild(RabbitMQApi.__name__), host=RABBIT_IP) - dockerhub_alerter = DockerhubAlerter(alerter_display_name, - dockerhub_alerter_logger, - rabbitmq, - ALERTER_PUBLISHING_QUEUE_SIZE - ) + dockerhub_alerter = DockerhubAlerter( + alerter_display_name, dockerhub_alerter_logger, rabbitmq, + ALERTER_PUBLISHING_QUEUE_SIZE + ) log_and_print("Successfully initialised {}".format( alerter_display_name), dockerhub_alerter_logger) break @@ -161,10 +159,8 @@ def _initialise_chainlink_node_alerter( logger=chainlink_alerter_logger.getChild(RabbitMQApi.__name__), host=RABBIT_IP) chainlink_alerter = ChainlinkNodeAlerter( - alerter_display_name, - chainlink_alerter_logger, - rabbitmq, - chainlink_alerts_configs_factory, + alerter_display_name, chainlink_alerter_logger, + rabbitmq, chainlink_alerts_configs_factory, ALERTER_PUBLISHING_QUEUE_SIZE ) log_and_print("Successfully initialised {}".format( @@ -194,11 +190,8 @@ def _initialise_chainlink_contract_alerter( logger=chainlink_alerter_logger.getChild(RabbitMQApi.__name__), host=RABBIT_IP) chainlink_alerter = ChainlinkContractAlerter( - alerter_display_name, - chainlink_alerter_logger, - rabbitmq, - chainlink_alerts_configs_factory, - ALERTER_PUBLISHING_QUEUE_SIZE + alerter_display_name, chainlink_alerter_logger, rabbitmq, + chainlink_alerts_configs_factory, ALERTER_PUBLISHING_QUEUE_SIZE ) log_and_print("Successfully initialised {}".format( alerter_display_name), chainlink_alerter_logger) @@ -227,10 +220,8 @@ def _initialise_evm_node_alerter( logger=evm_node_alerter_logger.getChild(RabbitMQApi.__name__), host=RABBIT_IP) evm_node_alerter = EVMNodeAlerter( - alerter_display_name, - evm_node_alerter_logger, - evm_alerts_configs_factory, - rabbitmq, + alerter_display_name, evm_node_alerter_logger, + evm_alerts_configs_factory, rabbitmq, ALERTER_PUBLISHING_QUEUE_SIZE ) log_and_print("Successfully initialised {}".format( @@ -305,9 +296,9 @@ def _initialise_cosmos_network_alerter( return cosmos_alerter -def start_system_alerter(system_alerts_config: SystemAlertsConfig, - chain: str) -> None: - system_alerter = _initialise_system_alerter(system_alerts_config, chain) +def start_system_alerter( + system_alerts_configs_factory: SystemAlertsConfigsFactory) -> None: + system_alerter = _initialise_system_alerter(system_alerts_configs_factory) start_alerter(system_alerter) diff --git a/alerter/src/alerter/alerters/contract/chainlink.py b/alerter/src/alerter/alerters/contract/chainlink.py index acffa2e7f..608e7f5e4 100644 --- a/alerter/src/alerter/alerters/contract/chainlink.py +++ b/alerter/src/alerter/alerters/contract/chainlink.py @@ -393,8 +393,8 @@ def _process_configs(self, method: pika.spec.Basic.Deliver, try: # Checking if the configuration is empty. If it is empty, remove the - # stored config (if it exists), and if it not add it to the list of - # configurations. + # stored config (if it exists), and if it is not, add it to the + # list of configurations. if bool(sent_configs): self.alerts_configs_factory.add_new_config(chain, sent_configs) diff --git a/alerter/src/alerter/alerters/node/chainlink.py b/alerter/src/alerter/alerters/node/chainlink.py index 5dfc33430..121c59022 100644 --- a/alerter/src/alerter/alerters/node/chainlink.py +++ b/alerter/src/alerter/alerters/node/chainlink.py @@ -274,31 +274,32 @@ def _process_prometheus_result(self, prom_data: Dict, MetricCode.TotalErroredJobRunsThreshold.value, meta_data['node_name'], meta_data['last_monitored'] ) - if str_to_bool(configs.eth_balance_amount['enabled']): - current = data['eth_balance_info']['current'] - sub_config = configs.eth_balance_amount + if str_to_bool(configs.balance_amount['enabled']): + current = data['balance_info']['current'] + sub_config = configs.balance_amount if current != {}: - self.alerting_factory.classify_thresholded_alert_reverse( - current['balance'], sub_config, - cl_alerts.EthBalanceIncreasedAboveThresholdAlert, - cl_alerts.EthBalanceDecreasedBelowThresholdAlert, + self.alerting_factory. \ + classify_thresholded_alert_reverse_chainlink_node( + current['balance'], sub_config, current['symbol'], + cl_alerts.BalanceIncreasedAboveThresholdAlert, + cl_alerts.BalanceDecreasedBelowThresholdAlert, data_for_alerting, meta_data['node_parent_id'], meta_data['node_id'], - MetricCode.EthBalanceThreshold.value, + MetricCode.BalanceThreshold.value, meta_data['node_name'], meta_data['last_monitored'] ) - if str_to_bool(configs.eth_balance_amount_increase['enabled']): - current = data['eth_balance_info']['current'] - previous = data['eth_balance_info']['previous'] - sub_config = configs.eth_balance_amount_increase + if str_to_bool(configs.balance_amount_increase['enabled']): + current = data['balance_info']['current'] + previous = data['balance_info']['previous'] + sub_config = configs.balance_amount_increase if current != {} and previous != {}: increase = current['balance'] - previous['balance'] self.alerting_factory.classify_conditional_alert( - cl_alerts.EthBalanceToppedUpAlert, + cl_alerts.BalanceToppedUpAlert, self._greater_than_condition_function, [current['balance'], previous['balance']], [ meta_data['node_name'], current['balance'], - increase, sub_config['severity'], + increase, current['symbol'], sub_config['severity'], meta_data['last_monitored'], meta_data['node_parent_id'], meta_data['node_id'] ], data_for_alerting @@ -555,8 +556,8 @@ def _process_configs(self, method: pika.spec.Basic.Deliver, try: # Checking if the configuration is empty. If it is empty, remove the - # stored config (if it exists), and if it not add it to the list of - # configurations. + # stored config (if it exists), and if it is not, add it to the + # list of configurations. if bool(sent_configs): self.alerts_configs_factory.add_new_config(chain, sent_configs) diff --git a/alerter/src/alerter/alerters/node/evm.py b/alerter/src/alerter/alerters/node/evm.py index dd7b6f242..2bd955106 100644 --- a/alerter/src/alerter/alerters/node/evm.py +++ b/alerter/src/alerter/alerters/node/evm.py @@ -313,15 +313,15 @@ def _process_configs(self, method: pika.spec.Basic.Deliver, try: # Checking if the configuration is empty. If it is empty, remove the - # stored config (if it exists), and if it not add it to the list of - # configurations. + # stored config (if it exists), and if it is not, add it to the + # list of configurations. if bool(sent_configs): self.alerts_configs_factory.add_new_config(chain, sent_configs) # We must reset the state since some thresholds might have # changed. A node's state will be recreated in the next # monitoring round automatically. Note we are sure that a - # parent_id is to be returned, as we have just added the config + # parent_id is to be returned, as we have just added the config. parent_id = self.alerts_configs_factory.get_parent_id(chain) self.alerting_factory.remove_chain_alerting_state(parent_id) else: @@ -332,8 +332,7 @@ def _process_configs(self, method: pika.spec.Basic.Deliver, # no storing took place, therefore in that case do nothing. parent_id = self.alerts_configs_factory.get_parent_id(chain) if parent_id: - self.alerting_factory.remove_chain_alerting_state( - parent_id) + self.alerting_factory.remove_chain_alerting_state(parent_id) self.alerts_configs_factory.remove_config(chain) except Exception as e: # Otherwise log and reject the message diff --git a/alerter/src/alerter/alerters/system.py b/alerter/src/alerter/alerters/system.py index f9925becd..f7e3c8a79 100644 --- a/alerter/src/alerter/alerters/system.py +++ b/alerter/src/alerter/alerters/system.py @@ -1,189 +1,103 @@ import copy import json import logging -from datetime import datetime, timedelta -from typing import Dict, Type, List +from datetime import datetime +from typing import Dict, List import pika.exceptions +from pika.adapters.blocking_connection import BlockingChannel -from src.alerter.alert_severities import Severity from src.alerter.alerters.alerter import Alerter -from src.alerter.alerts.system_alerts import ( - InvalidUrlAlert, OpenFileDescriptorsIncreasedAboveThresholdAlert, - SystemBackUpAgainAlert, - SystemCPUUsageDecreasedBelowThresholdAlert, - SystemCPUUsageIncreasedAboveThresholdAlert, - SystemRAMUsageDecreasedBelowThresholdAlert, - SystemRAMUsageIncreasedAboveThresholdAlert, SystemStillDownAlert, - SystemStorageUsageDecreasedBelowThresholdAlert, - SystemStorageUsageIncreasedAboveThresholdAlert, SystemWentDownAtAlert, - OpenFileDescriptorsDecreasedBelowThresholdAlert, MetricNotFoundErrorAlert, - ValidUrlAlert, MetricFoundAlert) -from src.alerter.grouped_alerts_metric_code import GroupedSystemAlertsMetricCode -from src.configs.alerts.system import SystemAlertsConfig +from src.alerter.alerts import system_alerts +from src.alerter.factory.system_alerting_factory import SystemAlertingFactory +from src.alerter.grouped_alerts_metric_code import \ + GroupedSystemAlertsMetricCode as MetricCode +from src.configs.factory.alerts.system_alerts import SystemAlertsConfigsFactory from src.message_broker.rabbitmq import RabbitMQApi from src.utils.constants.rabbitmq import ( - ALERT_EXCHANGE, HEALTH_CHECK_EXCHANGE, - SYS_ALERTER_INPUT_QUEUE_NAME_TEMPLATE, SYSTEM_ALERT_ROUTING_KEY, - SYSTEM_TRANSFORMED_DATA_ROUTING_KEY_TEMPLATE, TOPIC) + ALERT_EXCHANGE, HEALTH_CHECK_EXCHANGE, SYSTEM_ALERT_ROUTING_KEY, TOPIC, + SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME, CONFIG_EXCHANGE, + SYSTEM_TRANSFORMED_DATA_ROUTING_KEY, ALERTS_CONFIGS_ROUTING_KEY_GEN, + ALERTS_CONFIGS_ROUTING_KEY_CHAIN) from src.utils.exceptions import (MessageWasNotDeliveredException, ReceivedUnexpectedDataException, MetricNotFoundException, SystemIsDownException, InvalidUrlException) -from src.utils.timing import TimedTaskLimiter -from src.utils.types import (IncreasedAboveThresholdSystemAlert, - DecreasedBelowThresholdSystemAlert, str_to_bool, - convert_to_float) +from src.utils.types import str_to_bool class SystemAlerter(Alerter): - def __init__(self, alerter_name: str, - system_alerts_config: SystemAlertsConfig, - logger: logging.Logger, rabbitmq: RabbitMQApi, + """ + We will have one alerter for all systems. The system alerter doesn't + have to restart if the configurations change, as it will be listening + for both data and configs in the same queue. + """ + + def __init__(self, alerter_name: str, logger: logging.Logger, + system_alerts_configs_factory: SystemAlertsConfigsFactory, + rabbitmq: RabbitMQApi, max_queue_size: int = 0) -> None: super().__init__(alerter_name, logger, rabbitmq, max_queue_size) - self._system_alerts_config = system_alerts_config - self._queue_used = '' - self._invalid_url = {} - self._metric_not_found = {} - self._warning_sent = {} - self._critical_sent = {} - self._system_initial_alert_sent = {} - self._system_critical_timed_task_limiters = {} + self._alerts_configs_factory = system_alerts_configs_factory + self._alerting_factory = SystemAlertingFactory(logger) @property - def alerts_configs(self) -> SystemAlertsConfig: - return self._system_alerts_config - - def _create_state_for_system(self, system_id: str) -> None: - # This is for alerts were we want to check if an initial alert was sent - # for that metric, irrespective of the severity. - if system_id not in self._system_initial_alert_sent: - self._system_initial_alert_sent[system_id] = { - GroupedSystemAlertsMetricCode.SystemIsDown.value: False, - } - - # This is for alerts were we want to check if a warning alert was sent - # for a metric - if system_id not in self._warning_sent: - self._warning_sent[system_id] = { - GroupedSystemAlertsMetricCode.OpenFileDescriptorsThreshold - .value: False, - GroupedSystemAlertsMetricCode.SystemCPUUsageThreshold - .value: False, - GroupedSystemAlertsMetricCode.SystemStorageUsageThreshold - .value: False, - GroupedSystemAlertsMetricCode.SystemRAMUsageThreshold - .value: False, - } - - # This is for alerts were we want to check if a critical alert was sent - # for a metric - if system_id not in self._critical_sent: - self._critical_sent[system_id] = { - GroupedSystemAlertsMetricCode.OpenFileDescriptorsThreshold - .value: False, - GroupedSystemAlertsMetricCode.SystemCPUUsageThreshold - .value: False, - GroupedSystemAlertsMetricCode.SystemStorageUsageThreshold - .value: False, - GroupedSystemAlertsMetricCode.SystemRAMUsageThreshold - .value: False, - } + def alerts_configs_factory(self) -> SystemAlertsConfigsFactory: + return self._alerts_configs_factory - """ - These are used to indicate that the source that was having issues - in the form of `Invalid URL` or `Metric Not Found` is no longer - having those issues. By sending out the opposite alerts we can overwrite - the REDIS metric data which is displayed in the UI. This also informs - the user that the issue has been resolved. - """ - if system_id not in self._invalid_url: - self._invalid_url[system_id] = False - - if system_id not in self._metric_not_found: - self._metric_not_found[system_id] = False - - # initialise timed task limiters - if system_id not in self._system_critical_timed_task_limiters: - open_fd = self.alerts_configs.open_file_descriptors - cpu_use = self.alerts_configs.system_cpu_usage - storage = self.alerts_configs.system_storage_usage - ram_use = self.alerts_configs.system_ram_usage - is_down = self.alerts_configs.system_is_down - - self._system_critical_timed_task_limiters[system_id] = {} - system_critical_limiters = \ - self._system_critical_timed_task_limiters[system_id] - - open_fd_critical_repeat = convert_to_float( - open_fd['critical_repeat'], timedelta.max.total_seconds() - 1) - cpu_use_critical_repeat = convert_to_float( - cpu_use['critical_repeat'], timedelta.max.total_seconds() - 1) - storage_critical_repeat = convert_to_float( - storage['critical_repeat'], timedelta.max.total_seconds() - 1) - ram_use_critical_repeat = convert_to_float( - ram_use['critical_repeat'], timedelta.max.total_seconds() - 1) - is_down_critical_repeat = convert_to_float( - is_down['critical_repeat'], timedelta.max.total_seconds() - 1) - - system_critical_limiters[ - GroupedSystemAlertsMetricCode.OpenFileDescriptorsThreshold - .value] = TimedTaskLimiter(timedelta(seconds=float( - open_fd_critical_repeat))) - system_critical_limiters[ - GroupedSystemAlertsMetricCode.SystemCPUUsageThreshold.value] = \ - TimedTaskLimiter(timedelta(seconds=float( - cpu_use_critical_repeat))) - system_critical_limiters[ - GroupedSystemAlertsMetricCode.SystemStorageUsageThreshold - .value] = TimedTaskLimiter( - timedelta(seconds=float(storage_critical_repeat)) - ) - system_critical_limiters[ - GroupedSystemAlertsMetricCode.SystemRAMUsageThreshold.value] = \ - TimedTaskLimiter(timedelta(seconds=float( - ram_use_critical_repeat))) - system_critical_limiters[ - GroupedSystemAlertsMetricCode.SystemIsDown - .value] = TimedTaskLimiter( - timedelta(seconds=float(is_down_critical_repeat))) + @property + def alerting_factory(self) -> SystemAlertingFactory: + return self._alerting_factory def _initialise_rabbitmq(self) -> None: # An alerter is both a consumer and producer, therefore we need to # initialise both the consuming and producing configurations. self.rabbitmq.connect_till_successful() - # Set consuming configuration + # Set alerts consuming configuration self.logger.info("Creating '%s' exchange", ALERT_EXCHANGE) - self.rabbitmq.exchange_declare(exchange=ALERT_EXCHANGE, - exchange_type=TOPIC, passive=False, - durable=True, auto_delete=False, - internal=False) - self._queue_used = SYS_ALERTER_INPUT_QUEUE_NAME_TEMPLATE.format( - self.alerts_configs.parent_id) - self.logger.info("Creating queue '%s'", self._queue_used) - self.rabbitmq.queue_declare(self._queue_used, passive=False, - durable=True, exclusive=False, - auto_delete=False) - routing_key = SYSTEM_TRANSFORMED_DATA_ROUTING_KEY_TEMPLATE.format( - self.alerts_configs.parent_id) + self.rabbitmq.exchange_declare( + exchange=ALERT_EXCHANGE, exchange_type=TOPIC, passive=False, + durable=True, auto_delete=False, internal=False) + self.logger.info("Creating queue '%s'", + SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME) + self.rabbitmq.queue_declare(SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME, + passive=False, durable=True, + exclusive=False, auto_delete=False) self.logger.info("Binding queue '%s' to exchange '%s' with routing " - "key '%s'", self._queue_used, ALERT_EXCHANGE, - routing_key) - self.rabbitmq.queue_bind(queue=self._queue_used, - exchange=ALERT_EXCHANGE, - routing_key=routing_key) + "key '%s'", SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME, + ALERT_EXCHANGE, SYSTEM_TRANSFORMED_DATA_ROUTING_KEY) + self.rabbitmq.queue_bind( + queue=SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME, + exchange=ALERT_EXCHANGE, + routing_key=SYSTEM_TRANSFORMED_DATA_ROUTING_KEY) + + # Set configs consuming configuration + self.logger.info("Creating exchange '%s'", CONFIG_EXCHANGE) + self.rabbitmq.exchange_declare(CONFIG_EXCHANGE, TOPIC, False, True, + False, False) + self.logger.info("Binding queue '%s' to exchange '%s' with routing key " + "%s'", SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME, + CONFIG_EXCHANGE, ALERTS_CONFIGS_ROUTING_KEY_CHAIN) + self.rabbitmq.queue_bind( + SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME, CONFIG_EXCHANGE, + ALERTS_CONFIGS_ROUTING_KEY_CHAIN) + self.logger.info("Binding queue '%s' to exchange '%s' with routing key " + "%s'", SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME, + CONFIG_EXCHANGE, ALERTS_CONFIGS_ROUTING_KEY_GEN) + self.rabbitmq.queue_bind( + SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME, CONFIG_EXCHANGE, + ALERTS_CONFIGS_ROUTING_KEY_GEN) # Pre-fetch count is 5 times less the maximum queue size prefetch_count = round(self.publishing_queue.maxsize / 5) self.rabbitmq.basic_qos(prefetch_count=prefetch_count) self.logger.debug("Declaring consuming intentions") - self.rabbitmq.basic_consume(queue=self._queue_used, - on_message_callback=self._process_data, - auto_ack=False, exclusive=False, - consumer_tag=None) + self.rabbitmq.basic_consume( + queue=SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME, + on_message_callback=self._process_data, auto_ack=False, + exclusive=False, consumer_tag=None) # Set producing configuration self.logger.info("Setting delivery confirmation on RabbitMQ channel") @@ -192,36 +106,194 @@ def _initialise_rabbitmq(self) -> None: self.rabbitmq.exchange_declare(HEALTH_CHECK_EXCHANGE, TOPIC, False, True, False, False) - def _process_data(self, - ch: pika.adapters.blocking_connection.BlockingChannel, - method: pika.spec.Basic.Deliver, - properties: pika.spec.BasicProperties, - body: bytes) -> None: + def _process_data( + self, ch: BlockingChannel, method: pika.spec.Basic.Deliver, + properties: pika.spec.BasicProperties, body: bytes) -> None: + """ + This function calls the appropriate processing function, depending on + whether we received configs or transformed data. If none of this is + received the message is ignored. + :param ch: The rabbit channel + :param method: Pika method + :param properties: Pika properties + :param body: The message + :return: + """ + if method.routing_key == SYSTEM_TRANSFORMED_DATA_ROUTING_KEY: + self._process_transformed_data(method, body) + elif 'alerts_config' in method.routing_key: + self._process_configs(method, body) + else: + self.logger.debug("Received unexpected data %s with routing key %s", + body, method.routing_key) + self.rabbitmq.basic_ack(method.delivery_tag, False) + + def _process_result(self, transformer_data: Dict, + data_for_alerting: List) -> None: + meta_data = transformer_data['meta_data'] + data = transformer_data['data'] + + # Assert that the alerts_config has been received for the chain. + chain_name = self.alerts_configs_factory.get_chain_name( + meta_data['system_parent_id']) + if chain_name is not None: + configs = self.alerts_configs_factory.configs[chain_name] + self.alerting_factory.create_alerting_state( + meta_data['system_parent_id'], meta_data['system_id'], configs) + + # Check if some errors have been resolved + self.alerting_factory.classify_error_alert( + InvalidUrlException.code, system_alerts.InvalidUrlAlert, + system_alerts.ValidUrlAlert, data_for_alerting, + meta_data['system_parent_id'], meta_data['system_id'], + meta_data['system_name'], meta_data['last_monitored'], + MetricCode.InvalidUrl.value, "", "URL is now valid!." + ) + + self.alerting_factory.classify_error_alert( + MetricNotFoundException.code, + system_alerts.MetricNotFoundErrorAlert, + system_alerts.MetricFoundAlert, data_for_alerting, + meta_data['system_parent_id'], meta_data['system_id'], + meta_data['system_name'], meta_data['last_monitored'], + MetricCode.MetricNotFound.value, "", "Metrics have been found!." + ) + + # Check if the alert rules are satisfied for the metrics + if str_to_bool(configs.system_is_down['enabled']): + sub_config = configs.system_is_down + self.alerting_factory.classify_downtime_alert( + None, sub_config, + system_alerts.SystemWentDownAtAlert, + system_alerts.SystemStillDownAlert, + system_alerts.SystemBackUpAgainAlert, + data_for_alerting, + meta_data['system_parent_id'], meta_data['system_id'], + MetricCode.SystemIsDown.value, + meta_data['system_name'], meta_data['last_monitored'] + ) + + if str_to_bool(configs.open_file_descriptors['enabled']): + current = data['open_file_descriptors']['current'] + sub_config = configs.open_file_descriptors + self.alerting_factory.classify_thresholded_alert( + current, sub_config, + system_alerts. + OpenFileDescriptorsIncreasedAboveThresholdAlert, + system_alerts. + OpenFileDescriptorsDecreasedBelowThresholdAlert, + data_for_alerting, + meta_data['system_parent_id'], meta_data['system_id'], + MetricCode.OpenFileDescriptorsThreshold.value, + meta_data['system_name'], meta_data['last_monitored'] + ) + + if str_to_bool(configs.system_cpu_usage['enabled']): + current = data['system_cpu_usage']['current'] + sub_config = configs.system_cpu_usage + self.alerting_factory.classify_thresholded_alert( + current, sub_config, + system_alerts.SystemCPUUsageIncreasedAboveThresholdAlert, + system_alerts.SystemCPUUsageDecreasedBelowThresholdAlert, + data_for_alerting, + meta_data['system_parent_id'], meta_data['system_id'], + MetricCode.SystemCPUUsageThreshold.value, + meta_data['system_name'], meta_data['last_monitored'] + ) + + if str_to_bool(configs.system_ram_usage['enabled']): + current = data['system_ram_usage']['current'] + sub_config = configs.system_ram_usage + self.alerting_factory.classify_thresholded_alert( + current, sub_config, + system_alerts.SystemRAMUsageIncreasedAboveThresholdAlert, + system_alerts.SystemRAMUsageDecreasedBelowThresholdAlert, + data_for_alerting, + meta_data['system_parent_id'], meta_data['system_id'], + MetricCode.SystemRAMUsageThreshold.value, + meta_data['system_name'], meta_data['last_monitored'] + ) + + if str_to_bool(configs.system_storage_usage['enabled']): + current = data['system_storage_usage']['current'] + sub_config = configs.system_storage_usage + self.alerting_factory.classify_thresholded_alert( + current, sub_config, + system_alerts. + SystemStorageUsageIncreasedAboveThresholdAlert, + system_alerts. + SystemStorageUsageDecreasedBelowThresholdAlert, + data_for_alerting, + meta_data['system_parent_id'], meta_data['system_id'], + MetricCode.SystemStorageUsageThreshold.value, + meta_data['system_name'], meta_data['last_monitored'] + ) + + def _process_error(self, data: Dict, data_for_alerting: List) -> None: + meta_data = data['meta_data'] + + # Assert that the alerts_config has been received for the chain. + chain_name = self.alerts_configs_factory.get_chain_name( + meta_data['system_parent_id']) + if chain_name is not None: + configs = self.alerts_configs_factory.configs[chain_name] + self.alerting_factory.create_alerting_state( + meta_data['system_parent_id'], meta_data['system_id'], configs) + + # Detect whether some errors need to be raised, or have been + # resolved. + self.alerting_factory.classify_error_alert( + InvalidUrlException.code, system_alerts.InvalidUrlAlert, + system_alerts.ValidUrlAlert, data_for_alerting, + meta_data['system_parent_id'], meta_data['system_id'], + meta_data['system_name'], meta_data['time'], + MetricCode.InvalidUrl.value, data['message'], + "URL is now valid!", data['code'] + ) + + self.alerting_factory.classify_error_alert( + MetricNotFoundException.code, + system_alerts.MetricNotFoundErrorAlert, + system_alerts.MetricFoundAlert, data_for_alerting, + meta_data['system_parent_id'], meta_data['system_id'], + meta_data['system_name'], meta_data['time'], + MetricCode.MetricNotFound.value, data['message'], + "Metrics have been found!", data['code'] + ) + + # Check if the alert rules are satisfied for the metrics + if str_to_bool(configs.system_is_down['enabled']): + sub_config = configs.system_is_down + if data['code'] == SystemIsDownException.code: + self.alerting_factory.classify_downtime_alert( + data['data']['went_down_at']['current'], sub_config, + system_alerts.SystemWentDownAtAlert, + system_alerts.SystemStillDownAlert, + system_alerts.SystemBackUpAgainAlert, + data_for_alerting, + meta_data['system_parent_id'], meta_data['system_id'], + MetricCode.SystemIsDown.value, + meta_data['system_name'], meta_data['time'] + ) + + def _process_transformed_data(self, method: pika.spec.Basic.Deliver, + body: bytes) -> None: data_received = json.loads(body) self.logger.debug("Received %s. Now processing this data.", data_received) - parsed_routing_key = method.routing_key.split('.') processing_error = False data_for_alerting = [] try: - if self.alerts_configs.parent_id in parsed_routing_key: - if 'result' in data_received: - data = data_received['result']['data'] - meta_data = data_received['result']['meta_data'] - self._create_state_for_system(meta_data['system_id']) - self._process_results(data, meta_data, data_for_alerting) - elif 'error' in data_received: - self._create_state_for_system( - data_received['error']['meta_data']['system_id']) - self._process_errors(data_received['error'], - data_for_alerting) - else: - raise ReceivedUnexpectedDataException( - "{}: _process_data".format(self)) + if 'result' in data_received: + self._process_result(data_received['result'], + data_for_alerting) + elif 'error' in data_received: + self._process_error(data_received['error'], + data_for_alerting) else: raise ReceivedUnexpectedDataException( - "{}: _process_data".format(self)) + "{}: _process_transformed_data".format(self)) except Exception as e: self.logger.error("Error when processing %s", data_received) self.logger.exception(e) @@ -256,390 +328,54 @@ def _process_data(self, # reside in the publisher queue raise e - def _process_errors(self, error_data: Dict, - data_for_alerting: List) -> None: - is_down = self.alerts_configs.system_is_down - meta_data = error_data['meta_data'] - - if (self._invalid_url[meta_data['system_id']] - and int(error_data['code']) != InvalidUrlException.code): - alert = ValidUrlAlert( - meta_data['system_name'], "Url is valid!", - Severity.INFO.value, meta_data['time'], - meta_data['system_parent_id'], - meta_data['system_id'] - ) - data_for_alerting.append(alert.alert_data) - self.logger.debug("Successfully classified alert %s", - alert.alert_data) - self._invalid_url[meta_data['system_id']] = False - - if (self._metric_not_found[meta_data['system_id']] - and int(error_data['code']) != MetricNotFoundException.code): - alert = MetricFoundAlert( - meta_data['system_name'], "Metrics have been found!", - Severity.INFO.value, meta_data['time'], - meta_data['system_parent_id'], - meta_data['system_id'] - ) - data_for_alerting.append(alert.alert_data) - self.logger.debug("Successfully classified alert %s", - alert.alert_data) - self._metric_not_found[meta_data['system_id']] = False + def _process_configs(self, method: pika.spec.Basic.Deliver, + body: bytes) -> None: + sent_configs = json.loads(body) - """ - `MetricNotFoundErrorAlert` and `InvalidUrlAlert` repeat every - monitoring round (DEFAULT: 60 seconds). This is done without delays as - it's indication that the configuration is wrong. - """ - if int(error_data['code']) == MetricNotFoundException.code: - alert = MetricNotFoundErrorAlert( - meta_data['system_name'], error_data['message'], - Severity.ERROR.value, meta_data['time'], - meta_data['system_parent_id'], - meta_data['system_id'] - ) - data_for_alerting.append(alert.alert_data) - self.logger.debug("Successfully classified alert %s", - alert.alert_data) - self._metric_not_found[meta_data['system_id']] = True - elif int(error_data['code']) == InvalidUrlException.code: - alert = InvalidUrlAlert( - meta_data['system_name'], error_data['message'], - Severity.ERROR.value, meta_data['time'], - meta_data['system_parent_id'], - meta_data['system_id'] - ) - data_for_alerting.append(alert.alert_data) - self.logger.debug("Successfully classified alert %s", - alert.alert_data) - self._invalid_url[meta_data['system_id']] = True - elif int(error_data['code']) == SystemIsDownException.code: - if str_to_bool(is_down['enabled']): - data = error_data['data'] - current = float(data['went_down_at']['current']) - monitoring_timestamp = float(meta_data['time']) - monitoring_datetime = datetime.fromtimestamp( - monitoring_timestamp) - is_down_critical_limiter = \ - self._system_critical_timed_task_limiters[ - meta_data['system_id']][ - GroupedSystemAlertsMetricCode.SystemIsDown.value] - initial_downtime_alert_sent = \ - self._system_initial_alert_sent[meta_data['system_id']][ - GroupedSystemAlertsMetricCode.SystemIsDown.value] - downtime = monitoring_timestamp - current - critical_threshold = convert_to_float( - is_down['critical_threshold'], None) - critical_enabled = str_to_bool(is_down['critical_enabled']) - critical_repeat_enabled = str_to_bool( - is_down['critical_repeat_enabled']) - warning_threshold = convert_to_float( - is_down['warning_threshold'], None) - warning_enabled = str_to_bool(is_down['warning_enabled']) - - if not initial_downtime_alert_sent: - if critical_enabled and critical_threshold <= downtime: - alert = SystemWentDownAtAlert( - meta_data['system_name'], Severity.CRITICAL.value, - meta_data['time'], meta_data['system_parent_id'], - meta_data['system_id'] - ) - data_for_alerting.append(alert.alert_data) - self.logger.debug("Successfully classified alert %s", - alert.alert_data) - is_down_critical_limiter.set_last_time_that_did_task( - monitoring_datetime) - self._system_initial_alert_sent[meta_data['system_id']][ - GroupedSystemAlertsMetricCode.SystemIsDown - .value] = True - elif warning_enabled and warning_threshold <= downtime: - alert = SystemWentDownAtAlert( - meta_data['system_name'], Severity.WARNING.value, - meta_data['time'], meta_data['system_parent_id'], - meta_data['system_id'] - ) - data_for_alerting.append(alert.alert_data) - self.logger.debug("Successfully classified alert %s", - alert.alert_data) - is_down_critical_limiter.set_last_time_that_did_task( - monitoring_datetime) - self._system_initial_alert_sent[meta_data['system_id']][ - GroupedSystemAlertsMetricCode.SystemIsDown - .value] = True - else: - if critical_enabled and critical_repeat_enabled and \ - is_down_critical_limiter.can_do_task( - monitoring_datetime): - alert = SystemStillDownAlert( - meta_data['system_name'], downtime, - Severity.CRITICAL.value, - meta_data['time'], meta_data['system_parent_id'], - meta_data['system_id'] - ) - data_for_alerting.append(alert.alert_data) - self.logger.debug("Successfully classified alert %s", - alert.alert_data) - is_down_critical_limiter.set_last_time_that_did_task( - monitoring_datetime) - - def _process_results(self, metrics: Dict, meta_data: Dict, - data_for_alerting: List) -> None: - open_fd = self.alerts_configs.open_file_descriptors - cpu_use = self.alerts_configs.system_cpu_usage - storage = self.alerts_configs.system_storage_usage - ram_use = self.alerts_configs.system_ram_usage - is_down = self.alerts_configs.system_is_down - - if self._invalid_url[meta_data['system_id']]: - alert = ValidUrlAlert( - meta_data['system_name'], "Url is valid!", - Severity.INFO.value, meta_data['last_monitored'], - meta_data['system_parent_id'], - meta_data['system_id'] - ) - data_for_alerting.append(alert.alert_data) - self.logger.debug("Successfully classified alert %s", - alert.alert_data) - self._invalid_url[meta_data['system_id']] = False - if self._metric_not_found[meta_data['system_id']]: - alert = MetricFoundAlert( - meta_data['system_name'], "Metrics have been found!", - Severity.INFO.value, meta_data['last_monitored'], - meta_data['system_parent_id'], - meta_data['system_id'] - ) - data_for_alerting.append(alert.alert_data) - self.logger.debug("Successfully classified alert %s", - alert.alert_data) - self._metric_not_found[meta_data['system_id']] = False - - if str_to_bool(is_down['enabled']): - previous = metrics['went_down_at']['previous'] - is_down_critical_limiter = \ - self._system_critical_timed_task_limiters[ - meta_data['system_id']][ - GroupedSystemAlertsMetricCode.SystemIsDown.value] - initial_downtime_alert_sent = \ - self._system_initial_alert_sent[meta_data['system_id']][ - GroupedSystemAlertsMetricCode.SystemIsDown.value] - - if previous is not None or initial_downtime_alert_sent: - alert = SystemBackUpAgainAlert( - meta_data['system_name'], Severity.INFO.value, - meta_data['last_monitored'], meta_data['system_parent_id'], - meta_data['system_id'] - ) - data_for_alerting.append(alert.alert_data) - self.logger.debug("Successfully classified alert %s", - alert.alert_data) - self._system_initial_alert_sent[meta_data['system_id']][ - GroupedSystemAlertsMetricCode.SystemIsDown.value] = False - is_down_critical_limiter.reset() - - if str_to_bool(open_fd['enabled']): - current = metrics['open_file_descriptors']['current'] - if current is not None: - self._classify_alert( - current, open_fd, meta_data, - OpenFileDescriptorsIncreasedAboveThresholdAlert, - OpenFileDescriptorsDecreasedBelowThresholdAlert, - data_for_alerting, - GroupedSystemAlertsMetricCode.OpenFileDescriptorsThreshold - .value - ) - if str_to_bool(storage['enabled']): - current = metrics['system_storage_usage']['current'] - if current is not None: - self._classify_alert( - current, storage, meta_data, - SystemStorageUsageIncreasedAboveThresholdAlert, - SystemStorageUsageDecreasedBelowThresholdAlert, - data_for_alerting, - GroupedSystemAlertsMetricCode.SystemStorageUsageThreshold - .value - ) - if str_to_bool(cpu_use['enabled']): - current = metrics['system_cpu_usage']['current'] - if current is not None: - self._classify_alert( - current, cpu_use, meta_data, - SystemCPUUsageIncreasedAboveThresholdAlert, - SystemCPUUsageDecreasedBelowThresholdAlert, - data_for_alerting, - GroupedSystemAlertsMetricCode.SystemCPUUsageThreshold.value - ) - if str_to_bool(ram_use['enabled']): - current = metrics['system_ram_usage']['current'] - if current is not None: - self._classify_alert( - current, ram_use, meta_data, - SystemRAMUsageIncreasedAboveThresholdAlert, - SystemRAMUsageDecreasedBelowThresholdAlert, - data_for_alerting, - GroupedSystemAlertsMetricCode.SystemRAMUsageThreshold.value - ) + self.logger.debug("Received configs %s", sent_configs) - def _classify_alert( - self, current: float, config: Dict, meta_data: Dict, - increased_above_threshold_alert: - Type[IncreasedAboveThresholdSystemAlert], - decreased_below_threshold_alert: - Type[DecreasedBelowThresholdSystemAlert], data_for_alerting: List, - metric_name: str - ) -> None: - warning_threshold = convert_to_float(config['warning_threshold'], None) - critical_threshold = convert_to_float(config['critical_threshold'], - None) - warning_enabled = str_to_bool(config['warning_enabled']) - critical_enabled = str_to_bool(config['critical_enabled']) - critical_repeat_enabled = str_to_bool(config['critical_repeat_enabled']) - critical_limiter = self._system_critical_timed_task_limiters[ - meta_data['system_id']][metric_name] - warning_sent = self._warning_sent[meta_data['system_id']][metric_name] - critical_sent = self._critical_sent[meta_data['system_id']][metric_name] - monitoring_datetime = datetime.fromtimestamp( - float(meta_data['last_monitored'])) - - if warning_enabled and critical_enabled: - # If both warning and critical are enabled, we are combining alerts - # so that only one alert is received, depending on the current - # value. - - if (warning_threshold <= current < critical_threshold) \ - and (not warning_sent) and (not critical_sent): - # We do not use previous here so that an alert is raised if the - # alerter is restarted with a different configuration - - alert = increased_above_threshold_alert( - meta_data['system_name'], current, Severity.WARNING.value, - meta_data['last_monitored'], Severity.WARNING.value, - meta_data['system_parent_id'], meta_data['system_id'] - ) - data_for_alerting.append(alert.alert_data) - self.logger.debug("Successfully classified alert %s", - alert.alert_data) - self._warning_sent[meta_data['system_id']][metric_name] = True - elif warning_threshold < critical_threshold <= current: - - # We want to send a critical alert if no critical alert was - # sent yet, or repeating is enabled and the repeating threshold - # has been exceeded - if not critical_sent or ( - critical_repeat_enabled and - critical_limiter.can_do_task(monitoring_datetime)): - # We do not use previous here so that an alert is raised if - # the alerter is restarted with a different configuration - - alert = increased_above_threshold_alert( - meta_data['system_name'], current, - Severity.CRITICAL.value, meta_data['last_monitored'], - Severity.CRITICAL.value, meta_data['system_parent_id'], - meta_data['system_id'] - ) - data_for_alerting.append(alert.alert_data) - self.logger.debug("Successfully classified alert %s", - alert.alert_data) - critical_limiter.set_last_time_that_did_task( - monitoring_datetime) - self._critical_sent[meta_data['system_id']][ - metric_name] = True - elif current < warning_threshold and ( - warning_sent or critical_sent): - # We do not use previous here so that an alert is raised if the - # alerter is restarted with a different configuration - - alert = decreased_below_threshold_alert( - meta_data['system_name'], current, Severity.INFO.value, - meta_data['last_monitored'], Severity.WARNING.value, - meta_data['system_parent_id'], meta_data['system_id'] - ) - data_for_alerting.append(alert.alert_data) - self.logger.debug("Successfully classified alert %s", - alert.alert_data) - self._warning_sent[meta_data['system_id']][metric_name] = False - self._critical_sent[meta_data['system_id']][metric_name] = False - critical_limiter.reset() - elif current < critical_threshold and critical_sent: - # We need to use previous here so that we don't get repetitive - # alerts if this condition is met. - - alert = decreased_below_threshold_alert( - meta_data['system_name'], current, Severity.INFO.value, - meta_data['last_monitored'], Severity.CRITICAL.value, - meta_data['system_parent_id'], meta_data['system_id'] - ) - data_for_alerting.append(alert.alert_data) - self.logger.debug("Successfully classified alert %s", - alert.alert_data) - self._critical_sent[meta_data['system_id']][metric_name] = False - self._warning_sent[meta_data['system_id']][metric_name] = False - critical_limiter.reset() - elif warning_enabled: - # This case would be triggered if only warning is enabled. - - if (warning_threshold <= current) and not warning_sent: - alert = increased_above_threshold_alert( - meta_data['system_name'], current, - Severity.WARNING.value, - meta_data['last_monitored'], Severity.WARNING.value, - meta_data['system_parent_id'], meta_data['system_id'] - ) - data_for_alerting.append(alert.alert_data) - self.logger.debug("Successfully classified alert %s", - alert.alert_data) - self._warning_sent[meta_data['system_id']][ - metric_name] = True - elif current < warning_threshold and warning_sent: - alert = decreased_below_threshold_alert( - meta_data['system_name'], current, Severity.INFO.value, - meta_data['last_monitored'], Severity.WARNING.value, - meta_data['system_parent_id'], meta_data['system_id'] - ) - data_for_alerting.append(alert.alert_data) - self.logger.debug("Successfully classified alert %s", - alert.alert_data) - self._warning_sent[meta_data['system_id']][ - metric_name] = False - elif critical_enabled: - # This case would be triggered if only critical is enabled - - if critical_threshold <= current: - # We want to send a critical alert if no critical alert was - # sent yet, or repeating is enabled and the repeating threshold - # has been exceeded - if not critical_sent or ( - critical_repeat_enabled and - critical_limiter.can_do_task(monitoring_datetime)): - alert = increased_above_threshold_alert( - meta_data['system_name'], current, - Severity.CRITICAL.value, - meta_data['last_monitored'], Severity.CRITICAL.value, - meta_data['system_parent_id'], meta_data['system_id'] - ) - data_for_alerting.append(alert.alert_data) - self.logger.debug("Successfully classified alert %s", - alert.alert_data) - critical_limiter.set_last_time_that_did_task( - monitoring_datetime) - self._critical_sent[meta_data['system_id']][ - metric_name] = True - elif current < critical_threshold and critical_sent: - alert = decreased_below_threshold_alert( - meta_data['system_name'], current, Severity.INFO.value, - meta_data['last_monitored'], Severity.CRITICAL.value, - meta_data['system_parent_id'], meta_data['system_id'] - ) - data_for_alerting.append(alert.alert_data) - self.logger.debug("Successfully classified alert %s", - alert.alert_data) - self._critical_sent[meta_data['system_id']][ - metric_name] = False - critical_limiter.reset() + if 'DEFAULT' in sent_configs: + del sent_configs['DEFAULT'] + + if method.routing_key == ALERTS_CONFIGS_ROUTING_KEY_GEN: + chain = 'general' + else: + parsed_routing_key = method.routing_key.split('.') + chain = parsed_routing_key[1] + ' ' + parsed_routing_key[2] + + try: + # Checking if the configuration is empty. If it is empty, remove the + # stored config (if it exists), and if it is not, add it to the + # list of configurations. + if bool(sent_configs): + self.alerts_configs_factory.add_new_config(chain, sent_configs) + + # We must reset the state since some thresholds might have + # changed. A system's state will be recreated in the next + # monitoring round automatically. Note we are sure that a + # parent_id is to be returned, as we have just added the config. + parent_id = self.alerts_configs_factory.get_parent_id(chain) + self.alerting_factory.remove_chain_alerting_state(parent_id) + else: + # We must reset the state since a configuration is to be + # removed. Note that first we need to compute the parent_id, as + # the parent_id is obtained from the configs to be removed from + # the factory. If the parent_id cannot be found, it means that + # no storing took place, therefore in that case do nothing. + parent_id = self.alerts_configs_factory.get_parent_id(chain) + if parent_id: + self.alerting_factory.remove_chain_alerting_state(parent_id) + self.alerts_configs_factory.remove_config(chain) + except Exception as e: + # Otherwise log and reject the message + self.logger.error("Error when processing %s", sent_configs) + self.logger.exception(e) + + self.rabbitmq.basic_ack(method.delivery_tag, False) def _place_latest_data_on_queue(self, data_list: List) -> None: - # Place the latest alert data on the publishing queue. If the - # queue is full, remove old data. + # Place the latest alert data on the publishing queue. If the queue is + # full, remove old data. for alert in data_list: self.logger.debug("Adding %s to the publishing queue.", alert) if self.publishing_queue.full(): diff --git a/alerter/src/alerter/alerts/node/chainlink.py b/alerter/src/alerter/alerts/node/chainlink.py index 1469614d5..f07c3b04f 100644 --- a/alerter/src/alerter/alerts/node/chainlink.py +++ b/alerter/src/alerter/alerts/node/chainlink.py @@ -175,40 +175,43 @@ def __init__(self, origin_name: str, current_value: int, severity: str, GroupedChainlinkNodeAlertsMetricCode.TotalErroredJobRunsThreshold) -class EthBalanceIncreasedAboveThresholdAlert(Alert): - def __init__(self, origin_name: str, current_value: float, severity: str, - timestamp: float, threshold_severity: str, parent_id: str, - origin_id: str) -> None: +class BalanceIncreasedAboveThresholdAlert(Alert): + def __init__(self, origin_name: str, current_value: float, symbol: str, + severity: str, timestamp: float, threshold_severity: str, + parent_id: str, origin_id: str) -> None: super().__init__( - ChainlinkNodeAlertCode.EthBalanceIncreasedAboveThresholdAlert, - "{} Ethereum balance has INCREASED above {} threshold. Current " - "value: {}.".format(origin_name, threshold_severity, current_value), + ChainlinkNodeAlertCode.BalanceIncreasedAboveThresholdAlert, + "{} account balance has INCREASED above {} threshold. Current " + "value: {} {}.".format( + origin_name, threshold_severity, current_value, symbol), severity, timestamp, parent_id, origin_id, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold) + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold) -class EthBalanceDecreasedBelowThresholdAlert(Alert): - def __init__(self, origin_name: str, current_value: float, severity: str, - timestamp: float, threshold_severity: str, parent_id: str, - origin_id: str) -> None: +class BalanceDecreasedBelowThresholdAlert(Alert): + def __init__(self, origin_name: str, current_value: float, symbol: str, + severity: str, timestamp: float, threshold_severity: str, + parent_id: str, origin_id: str) -> None: super().__init__( - ChainlinkNodeAlertCode.EthBalanceDecreasedBelowThresholdAlert, - "{} Ethereum balance has DECREASED below {} threshold. Current " - "value: {}.".format(origin_name, threshold_severity, current_value), + ChainlinkNodeAlertCode.BalanceDecreasedBelowThresholdAlert, + "{} account balance has DECREASED below {} threshold. Current " + "value: {} {}.".format( + origin_name, threshold_severity, current_value, symbol), severity, timestamp, parent_id, origin_id, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold) + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold) -class EthBalanceToppedUpAlert(Alert): +class BalanceToppedUpAlert(Alert): def __init__(self, origin_name: str, current_value: float, increase: float, - severity: str, timestamp: float, parent_id: str, + symbol: str, severity: str, timestamp: float, parent_id: str, origin_id: str) -> None: super().__init__( - ChainlinkNodeAlertCode.EthBalanceToppedUpAlert, - "{} Ethereum balance has been topped up by {} ETH. Current " - "value: {}.".format(origin_name, increase, current_value), + ChainlinkNodeAlertCode.BalanceToppedUpAlert, + "{} account balance has been topped up by {} {}. Current " + "value: {} {}.".format( + origin_name, increase, symbol, current_value, symbol), severity, timestamp, parent_id, origin_id, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceTopUp) + GroupedChainlinkNodeAlertsMetricCode.BalanceTopUp) class InvalidUrlAlert(Alert): diff --git a/alerter/src/alerter/factory/chainlink_node_alerting_factory.py b/alerter/src/alerter/factory/chainlink_node_alerting_factory.py index 86ec8a119..2350ab493 100644 --- a/alerter/src/alerter/factory/chainlink_node_alerting_factory.py +++ b/alerter/src/alerter/factory/chainlink_node_alerting_factory.py @@ -1,6 +1,8 @@ import logging -from datetime import timedelta +from datetime import timedelta, datetime +from typing import Any, Dict, Type, List +from src.alerter.alert_severities import Severity from src.alerter.factory.alerting_factory import AlertingFactory from src.alerter.grouped_alerts_metric_code.node.chainlink_node_metric_code \ import GroupedChainlinkNodeAlertsMetricCode as AlertsMetricCode @@ -8,6 +10,8 @@ from src.utils.configs import parse_alert_time_thresholds from src.utils.timing import (TimedTaskTracker, TimedTaskLimiter, OccurrencesInTimePeriodTracker) +from src.utils.types import (IncreasedAboveThresholdAlert, convert_to_float, + DecreasedBelowThresholdAlert, str_to_bool) class ChainlinkNodeAlertingFactory(AlertingFactory): @@ -74,7 +78,7 @@ def create_alerting_state( AlertsMetricCode.MaxUnconfirmedBlocksThreshold.value: False, AlertsMetricCode.NoOfUnconfirmedTxsThreshold.value: False, AlertsMetricCode.TotalErroredJobRunsThreshold.value: False, - AlertsMetricCode.EthBalanceThreshold.value: False, + AlertsMetricCode.BalanceThreshold.value: False, AlertsMetricCode.NodeIsDown.value: False, AlertsMetricCode.PrometheusSourceIsDown.value: False } @@ -84,7 +88,7 @@ def create_alerting_state( AlertsMetricCode.MaxUnconfirmedBlocksThreshold.value: False, AlertsMetricCode.NoOfUnconfirmedTxsThreshold.value: False, AlertsMetricCode.TotalErroredJobRunsThreshold.value: False, - AlertsMetricCode.EthBalanceThreshold.value: False, + AlertsMetricCode.BalanceThreshold.value: False, AlertsMetricCode.NodeIsDown.value: False, } error_sent = { @@ -113,8 +117,8 @@ def create_alerting_state( 'critical_repeat'], cl_node_alerts_config.run_status_update_total ) - eth_balance_thresholds = parse_alert_time_thresholds( - ['critical_repeat'], cl_node_alerts_config.eth_balance_amount + balance_thresholds = parse_alert_time_thresholds( + ['critical_repeat'], cl_node_alerts_config.balance_amount ) node_is_down_thresholds = parse_alert_time_thresholds( ['warning_threshold', 'critical_threshold', @@ -174,8 +178,8 @@ def create_alerting_state( AlertsMetricCode.TotalErroredJobRunsThreshold.value: TimedTaskLimiter(timedelta(seconds=error_jobs_thresholds[ 'critical_repeat'])), - AlertsMetricCode.EthBalanceThreshold.value: TimedTaskLimiter( - timedelta(seconds=eth_balance_thresholds[ + AlertsMetricCode.BalanceThreshold.value: TimedTaskLimiter( + timedelta(seconds=balance_thresholds[ 'critical_repeat'])), AlertsMetricCode.NodeIsDown.value: TimedTaskLimiter(timedelta( seconds=node_is_down_thresholds['critical_repeat'])), @@ -212,3 +216,131 @@ def remove_chain_alerting_state(self, parent_id: str) -> None: """ if parent_id in self.alerting_state: del self.alerting_state[parent_id] + + def classify_thresholded_alert_reverse_chainlink_node( + self, current: Any, config: Dict, symbol: str, + increased_above_threshold_alert: Type[IncreasedAboveThresholdAlert], + decreased_below_threshold_alert: Type[DecreasedBelowThresholdAlert], + data_for_alerting: List, parent_id: str, monitorable_id: str, + metric_name: str, monitorable_name: str, monitoring_timestamp: float + ) -> None: + """ + We are overwriting `classify_thresholded_alert_reverse` of the + inherited class. + This function raises a critical/warning decrease below threshold alert + if the current value is smaller than the respective thresholds. If the + critical repeat time is constantly elapsed, the decrease alert is + re-raised with a critical severity each time. Also, an increase above + threshold info alert is raised whenever the current value is less + than a threshold. Note, a warning decrease is re-raised if + warning_threshold >= current > critical_threshold >= previous. This is + done so that in the UI the respective metric is shown in warning state + and not in info state. + :param current: Current metric value + :param config: The metric's configuration to obtain the thresholds + :param symbol: The currency symbol of the chain. + :param increased_above_threshold_alert: The alert to be raised if the + current value is no longer smaller than a threshold + :param decreased_below_threshold_alert: The alert to be raised if the + current value is smaller than a threshold + :param data_for_alerting: The list to be appended with alerts + :param parent_id: The id of the base chain + :param monitorable_id: The id of the monitorable + :param metric_name: The name of the metric + :param monitorable_name: The name of the monitorable + :param monitoring_timestamp: The data timestamp + :return: None + """ + # Parse warning thresholds and limiters + warning_enabled = str_to_bool(config['warning_enabled']) + warning_threshold = convert_to_float(config['warning_threshold'], None) + warning_sent = self.alerting_state[parent_id][monitorable_id][ + 'warning_sent'] + + # Parse critical thresholds and limiters + critical_enabled = str_to_bool(config['critical_enabled']) + critical_threshold = convert_to_float(config['critical_threshold'], + None) + critical_repeat_enabled = str_to_bool(config['critical_repeat_enabled']) + critical_repeat_limiter = self.alerting_state[parent_id][ + monitorable_id]['critical_repeat_timer'][metric_name] + critical_sent = self.alerting_state[parent_id][monitorable_id][ + 'critical_sent'] + + monitoring_datetime = datetime.fromtimestamp(monitoring_timestamp) + + # First check if there was an increase so that an info alert is raised. + # First check for critical as it is expected that + # warning_threshold >= critical_threshold + + if critical_sent[metric_name] and current > critical_threshold: + alert = increased_above_threshold_alert( + monitorable_name, current, symbol, Severity.INFO.value, + monitoring_timestamp, Severity.CRITICAL.value, parent_id, + monitorable_id) + data_for_alerting.append(alert.alert_data) + self.component_logger.debug("Successfully classified alert %s", + alert.alert_data) + self.alerting_state[parent_id][monitorable_id][ + 'critical_sent'][metric_name] = False + critical_repeat_limiter.reset() + + # If this is the case we still need to raise a warning alert to + # show the correct metric state in the UI. + if warning_sent[metric_name] and current <= warning_threshold: + self.alerting_state[parent_id][monitorable_id]['warning_sent'][ + metric_name] = False + + if warning_sent[metric_name] and current > warning_threshold: + alert = increased_above_threshold_alert( + monitorable_name, current, symbol, Severity.INFO.value, + monitoring_timestamp, Severity.WARNING.value, parent_id, + monitorable_id) + data_for_alerting.append(alert.alert_data) + self.component_logger.debug("Successfully classified alert %s", + alert.alert_data) + self.alerting_state[parent_id][monitorable_id]['warning_sent'][ + metric_name] = False + + # Now check if the current value is greater than any of the thresholds. + # First check for critical and do not raise a warning alert if we are + # immediately in critical state. + + if critical_enabled and current <= critical_threshold: + if not critical_sent[metric_name]: + alert = decreased_below_threshold_alert( + monitorable_name, current, symbol, Severity.CRITICAL.value, + monitoring_timestamp, Severity.CRITICAL.value, parent_id, + monitorable_id) + data_for_alerting.append(alert.alert_data) + self.component_logger.debug("Successfully classified alert %s", + alert.alert_data) + self.alerting_state[parent_id][monitorable_id][ + 'critical_sent'][metric_name] = True + critical_repeat_limiter.set_last_time_that_did_task( + monitoring_datetime) + elif (critical_repeat_enabled + and critical_repeat_limiter.can_do_task(monitoring_datetime)): + alert = decreased_below_threshold_alert( + monitorable_name, current, symbol, Severity.CRITICAL.value, + monitoring_timestamp, Severity.CRITICAL.value, parent_id, + monitorable_id) + data_for_alerting.append(alert.alert_data) + self.component_logger.debug("Successfully classified alert %s", + alert.alert_data) + critical_repeat_limiter.set_last_time_that_did_task( + monitoring_datetime) + + if (warning_enabled + and not warning_sent[metric_name] + and not critical_sent[metric_name] + and current <= warning_threshold): + alert = decreased_below_threshold_alert( + monitorable_name, current, symbol, Severity.WARNING.value, + monitoring_timestamp, Severity.WARNING.value, parent_id, + monitorable_id) + data_for_alerting.append(alert.alert_data) + self.component_logger.debug("Successfully classified alert %s", + alert.alert_data) + self.alerting_state[parent_id][monitorable_id][ + 'warning_sent'][metric_name] = True diff --git a/alerter/src/alerter/factory/system_alerting_factory.py b/alerter/src/alerter/factory/system_alerting_factory.py new file mode 100644 index 000000000..b0ca24e85 --- /dev/null +++ b/alerter/src/alerter/factory/system_alerting_factory.py @@ -0,0 +1,175 @@ +import logging +from datetime import timedelta + +from src.alerter.factory.alerting_factory import AlertingFactory +from src.alerter.grouped_alerts_metric_code.system \ + import GroupedSystemAlertsMetricCode as AlertsMetricCode +from src.configs.alerts.system import SystemAlertsConfig +from src.utils.configs import parse_alert_time_thresholds +from src.utils.timing import TimedTaskTracker, TimedTaskLimiter + + +class SystemAlertingFactory(AlertingFactory): + """ + This class is in charge of alerting and managing the alerting state for the + system alerter. The alerting_state dict is to be structured as follows: + { + : { + : { + Optional[warning_sent]: { + GroupedSystemAlertsMetricCode.value: bool + }, + Optional[critical_sent]: { + GroupedSystemAlertsMetricCode.value: bool + }, + Optional[error_sent]: { + GroupedSystemAlertsMetricCode.value: bool + }, + Optional[warning_window_timer]: { + GroupedSystemAlertsMetricCode.value: TimedTaskTracker + }, + Optional[critical_window_timer]: { + GroupedSystemAlertsMetricCode.value: TimedTaskTracker + }, + Optional[critical_repeat_timer]: { + GroupedSystemAlertsMetricCode.value: TimedTaskLimiter + } + } + } + } + """ + + def __init__(self, component_logger: logging.Logger) -> None: + super().__init__(component_logger) + + def create_alerting_state(self, parent_id: str, system_id: str, + system_alerts_config: SystemAlertsConfig) -> None: + """ + If no state is already stored, this function will create a new alerting + state for a system based on the passed alerts config. + :param parent_id: The id of the chain + :param system_id: The id of the system + :param system_alerts_config: The system alerts configuration + :return: None + """ + + if parent_id not in self.alerting_state: + self.alerting_state[parent_id] = {} + + if system_id not in self.alerting_state[parent_id]: + warning_sent = { + AlertsMetricCode.OpenFileDescriptorsThreshold.value: False, + AlertsMetricCode.SystemCPUUsageThreshold.value: False, + AlertsMetricCode.SystemRAMUsageThreshold.value: False, + AlertsMetricCode.SystemStorageUsageThreshold.value: False, + AlertsMetricCode.SystemIsDown.value: False + } + critical_sent = { + AlertsMetricCode.OpenFileDescriptorsThreshold.value: False, + AlertsMetricCode.SystemCPUUsageThreshold.value: False, + AlertsMetricCode.SystemRAMUsageThreshold.value: False, + AlertsMetricCode.SystemStorageUsageThreshold.value: False, + AlertsMetricCode.SystemIsDown.value: False + } + error_sent = { + AlertsMetricCode.InvalidUrl.value: False, + AlertsMetricCode.MetricNotFound.value: False, + } + + open_file_descriptors_thresholds = parse_alert_time_thresholds( + ['warning_threshold', 'critical_threshold', 'critical_repeat'], + system_alerts_config.open_file_descriptors) + system_cpu_usage_thresholds = parse_alert_time_thresholds( + ['warning_threshold', 'critical_threshold', 'critical_repeat'], + system_alerts_config.system_cpu_usage) + system_ram_usage_thresholds = parse_alert_time_thresholds( + ['warning_threshold', 'critical_threshold', 'critical_repeat'], + system_alerts_config.system_ram_usage + ) + system_storage_usage_thresholds = parse_alert_time_thresholds( + ['warning_threshold', 'critical_threshold', 'critical_repeat'], + system_alerts_config.system_storage_usage + ) + system_is_down_thresholds = parse_alert_time_thresholds( + ['warning_threshold', 'critical_threshold', 'critical_repeat'], + system_alerts_config.system_is_down + ) + + warning_window_timer = { + AlertsMetricCode.OpenFileDescriptorsThreshold.value: + TimedTaskTracker(timedelta( + seconds=open_file_descriptors_thresholds[ + 'warning_threshold'])), + AlertsMetricCode.SystemCPUUsageThreshold.value: + TimedTaskTracker(timedelta( + seconds=system_cpu_usage_thresholds['warning_threshold'] + )), + AlertsMetricCode.SystemRAMUsageThreshold.value: + TimedTaskTracker(timedelta( + seconds=system_ram_usage_thresholds[ + 'warning_threshold'])), + AlertsMetricCode.SystemStorageUsageThreshold.value: + TimedTaskTracker(timedelta( + seconds=system_storage_usage_thresholds[ + 'warning_threshold'])), + AlertsMetricCode.SystemIsDown.value: TimedTaskTracker(timedelta( + seconds=system_is_down_thresholds['warning_threshold'])) + } + critical_window_timer = { + AlertsMetricCode.OpenFileDescriptorsThreshold.value: + TimedTaskTracker(timedelta( + seconds=open_file_descriptors_thresholds[ + 'critical_threshold'])), + AlertsMetricCode.SystemCPUUsageThreshold.value: + TimedTaskTracker(timedelta( + seconds=system_cpu_usage_thresholds[ + 'critical_threshold'])), + AlertsMetricCode.SystemRAMUsageThreshold.value: + TimedTaskTracker(timedelta( + seconds=system_ram_usage_thresholds[ + 'critical_threshold'])), + AlertsMetricCode.SystemStorageUsageThreshold.value: + TimedTaskTracker(timedelta( + seconds=system_storage_usage_thresholds[ + 'critical_threshold'])), + AlertsMetricCode.SystemIsDown.value: TimedTaskTracker(timedelta( + seconds=system_is_down_thresholds['critical_threshold'])) + } + critical_repeat_timer = { + AlertsMetricCode.OpenFileDescriptorsThreshold.value: + TimedTaskLimiter(timedelta( + seconds=open_file_descriptors_thresholds[ + 'critical_repeat'])), + AlertsMetricCode.SystemCPUUsageThreshold.value: + TimedTaskLimiter(timedelta( + seconds=system_cpu_usage_thresholds['critical_repeat']) + ), + AlertsMetricCode.SystemRAMUsageThreshold.value: + TimedTaskLimiter(timedelta( + seconds=system_ram_usage_thresholds['critical_repeat']) + ), + AlertsMetricCode.SystemStorageUsageThreshold.value: + TimedTaskLimiter(timedelta( + seconds=system_storage_usage_thresholds[ + 'critical_repeat'])), + AlertsMetricCode.SystemIsDown.value: TimedTaskLimiter(timedelta( + seconds=system_is_down_thresholds['critical_repeat'])) + } + + self.alerting_state[parent_id][system_id] = { + 'warning_sent': warning_sent, + 'critical_sent': critical_sent, + 'error_sent': error_sent, + 'warning_window_timer': warning_window_timer, + 'critical_window_timer': critical_window_timer, + 'critical_repeat_timer': critical_repeat_timer + } + + def remove_chain_alerting_state(self, parent_id: str) -> None: + """ + This function deletes an entire alerting state for a chain. + :param parent_id: The id of the chain to be deleted + :return: None + """ + if parent_id in self.alerting_state: + del self.alerting_state[parent_id] diff --git a/alerter/src/alerter/grouped_alerts_metric_code/node/chainlink_node_metric_code.py b/alerter/src/alerter/grouped_alerts_metric_code/node/chainlink_node_metric_code.py index f3614f1be..93a58f3be 100644 --- a/alerter/src/alerter/grouped_alerts_metric_code/node/chainlink_node_metric_code.py +++ b/alerter/src/alerter/grouped_alerts_metric_code/node/chainlink_node_metric_code.py @@ -10,8 +10,8 @@ class GroupedChainlinkNodeAlertsMetricCode(GroupedAlertsMetricCode): 'cl_tx_manager_gas_bump_exceeds_limit_total') NoOfUnconfirmedTxsThreshold = 'cl_unconfirmed_transactions' TotalErroredJobRunsThreshold = 'cl_run_status_update_total' - EthBalanceThreshold = 'cl_eth_balance_amount' - EthBalanceTopUp = 'cl_eth_balance_amount_increase' + BalanceThreshold = 'cl_balance_amount' + BalanceTopUp = 'cl_balance_amount_increase' InvalidUrl = 'cl_invalid_url' MetricNotFound = 'cl_metric_not_found' NodeIsDown = 'cl_node_is_down' diff --git a/alerter/src/alerter/managers/system.py b/alerter/src/alerter/managers/system.py index 39f7cb5c6..7f168a5f5 100644 --- a/alerter/src/alerter/managers/system.py +++ b/alerter/src/alerter/managers/system.py @@ -1,9 +1,9 @@ import copy import json import logging -import multiprocessing import sys from datetime import datetime +from multiprocessing import Process from types import FrameType from typing import Dict @@ -14,18 +14,16 @@ from src.alerter.alerters.system import SystemAlerter from src.alerter.alerts.internal_alerts import ComponentResetAlert from src.alerter.managers.manager import AlertersManager -from src.configs.alerts.system import SystemAlertsConfig +from src.configs.factory.alerts.system_alerts import SystemAlertsConfigsFactory from src.message_broker.rabbitmq import RabbitMQApi -from src.utils.constants.names import SYSTEM_ALERTER_NAME_TEMPLATE +from src.utils.constants.names import SYSTEM_ALERTER_NAME from src.utils.constants.rabbitmq import ( HEALTH_CHECK_EXCHANGE, CONFIG_EXCHANGE, - SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME, + SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME, SYS_ALERTERS_MAN_HEARTBEAT_QUEUE_NAME, PING_ROUTING_KEY, - ALERTS_CONFIGS_ROUTING_KEY_CHAIN, - ALERTS_CONFIGS_ROUTING_KEY_GEN, ALERT_EXCHANGE, - SYSTEM_ALERT_ROUTING_KEY, TOPIC) -from src.utils.exceptions import (ParentIdsMissMatchInAlertsConfiguration, - MessageWasNotDeliveredException) + ALERTS_CONFIGS_ROUTING_KEY_CHAIN, ALERTS_CONFIGS_ROUTING_KEY_GEN, + ALERT_EXCHANGE, SYSTEM_ALERT_ROUTING_KEY, TOPIC) +from src.utils.exceptions import MessageWasNotDeliveredException from src.utils.logging import log_and_print @@ -34,16 +32,28 @@ class SystemAlertersManager(AlertersManager): def __init__(self, logger: logging.Logger, manager_name: str, rabbitmq: RabbitMQApi) -> None: super().__init__(logger, manager_name, rabbitmq) - self._systems_alerts_configs = {} - self._parent_id_process_dict = {} + self._system_alerts_config_factory = SystemAlertsConfigsFactory() + self._alerter_process_dict = {} + self._configs_processor_helper = { + SYSTEM_ALERTER_NAME: { + 'alerterClass': SystemAlerter, + 'factory': self.system_alerts_config_factory, + 'routing_key': SYSTEM_ALERT_ROUTING_KEY, + 'starter': start_system_alerter, + } + } @property - def systems_alerts_configs(self) -> Dict: - return self._systems_alerts_configs + def alerter_process_dict(self) -> Dict: + return self._alerter_process_dict @property - def parent_id_process_dict(self) -> Dict: - return self._parent_id_process_dict + def system_alerts_config_factory(self) -> SystemAlertsConfigsFactory: + return self._system_alerts_config_factory + + @property + def configs_processor_helper(self) -> Dict: + return self._configs_processor_helper def _initialise_rabbitmq(self) -> None: self.rabbitmq.connect_till_successful() @@ -66,34 +76,35 @@ def _initialise_rabbitmq(self) -> None: self.rabbitmq.basic_consume(SYS_ALERTERS_MAN_HEARTBEAT_QUEUE_NAME, self._process_ping, True, False, None) + # Setting up routing keys and queues for configuration consumption self.logger.info("Creating exchange '%s'", CONFIG_EXCHANGE) self.rabbitmq.exchange_declare(CONFIG_EXCHANGE, TOPIC, False, True, False, False) self.logger.info("Creating queue '%s'", - SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME) - self.rabbitmq.queue_declare(SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME, + SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME) + self.rabbitmq.queue_declare(SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME, False, True, False, False) self.logger.info("Binding queue '%s' to exchange '%s' with routing key " - "%s'", SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME, - CONFIG_EXCHANGE, - ALERTS_CONFIGS_ROUTING_KEY_CHAIN) - self.rabbitmq.queue_bind(SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME, + "%s'", SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME, + CONFIG_EXCHANGE, ALERTS_CONFIGS_ROUTING_KEY_CHAIN) + self.rabbitmq.queue_bind(SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME, CONFIG_EXCHANGE, ALERTS_CONFIGS_ROUTING_KEY_CHAIN) self.logger.info("Binding queue '%s' to exchange '%s' with routing key " - "'%s'", SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME, + "'%s'", SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME, CONFIG_EXCHANGE, ALERTS_CONFIGS_ROUTING_KEY_GEN) - self.rabbitmq.queue_bind(SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME, + self.rabbitmq.queue_bind(SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME, CONFIG_EXCHANGE, ALERTS_CONFIGS_ROUTING_KEY_GEN) self.logger.info("Declaring consuming intentions on %s", - SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME) - self.rabbitmq.basic_consume(SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME, + SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME) + self.rabbitmq.basic_consume(SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME, self._process_configs, False, False, None) # Declare publishing intentions self.logger.info("Creating '%s' exchange", ALERT_EXCHANGE) + # Declare exchange to send data to self.rabbitmq.exchange_declare(exchange=ALERT_EXCHANGE, exchange_type=TOPIC, passive=False, @@ -102,115 +113,6 @@ def _initialise_rabbitmq(self) -> None: self.logger.info("Setting delivery confirmation on RabbitMQ channel") self.rabbitmq.confirm_delivery() - def _terminate_and_join_chain_alerter_processes( - self, chain: str) -> None: - # Go through all the processes and find the chain whose - # process should be terminated. Note that here we are not sending - # any internal alerts, therefore if a chain is removed completely some - # metrics might continue to live in redis until that chain is added - # back. This is not a bug because any removed chains will no longer - # appear in the list of monitorables for the UI. - for parent_id, parent_info in list( - self._parent_id_process_dict.items()): - - if self._parent_id_process_dict[parent_id]['chain'] == chain: - log_and_print("Terminating alerter process for chain " - "{}".format(chain), self.logger) - # Terminate the process and join it - self._parent_id_process_dict[parent_id]['process'].terminate() - self._parent_id_process_dict[parent_id]['process'].join() - # Delete key from process and configs as they aren't needed - # anymore - del self._parent_id_process_dict[parent_id] - del self._systems_alerts_configs[parent_id] - - def _create_and_start_alerter_process( - self, system_alerts_config: SystemAlertsConfig, parent_id: str, - chain: str) -> None: - alerter_name = SYSTEM_ALERTER_NAME_TEMPLATE.format(chain) - - # Send an internal alert to reset all the REDIS metrics for this chain - alert = ComponentResetAlert( - alerter_name, datetime.now().timestamp(), SystemAlerter.__name__, - parent_id, chain) - self._push_latest_data_to_queue_and_send(alert.alert_data) - - process = multiprocessing.Process(target=start_system_alerter, - args=(system_alerts_config, chain)) - process.daemon = True - log_and_print("Creating a new process for the system alerter " - "of {}".format(chain), self.logger) - process.start() - self._parent_id_process_dict[parent_id] = {} - self._parent_id_process_dict[parent_id]['component_name'] = alerter_name - self._parent_id_process_dict[parent_id]['process'] = process - self._parent_id_process_dict[parent_id]['chain'] = chain - - def _process_configs( - self, ch: BlockingChannel, method: pika.spec.Basic.Deliver, - properties: pika.spec.BasicProperties, body: bytes) -> None: - sent_configs = json.loads(body) - - self.logger.debug("Received configs %s", sent_configs) - - if 'DEFAULT' in sent_configs: - del sent_configs['DEFAULT'] - - if method.routing_key == ALERTS_CONFIGS_ROUTING_KEY_GEN: - chain = 'general' - else: - parsed_routing_key = method.routing_key.split('.') - chain = parsed_routing_key[1] + ' ' + parsed_routing_key[2] - - try: - """ - Send an internal alert to clear every metric from Redis for the - chain in question, and terminate the process for the received - config. Note that all this happens if a configuration is modified - or deleted. - """ - self._terminate_and_join_chain_alerter_processes(chain) - - # Checking if we received a configuration, therefore we start the - # process again - if bool(sent_configs): - # Check if all the parent_ids in the received configuration - # are the same - parent_id = sent_configs['1']['parent_id'] - for _, config in sent_configs.items(): - if parent_id != config['parent_id']: - raise ParentIdsMissMatchInAlertsConfiguration( - "{}: _process_data".format(self)) - filtered = {} - for _, config in sent_configs.items(): - filtered[config['name']] = copy.deepcopy(config) - - system_alerts_config = SystemAlertsConfig( - parent_id=parent_id, - open_file_descriptors=filtered['open_file_descriptors'], - system_cpu_usage=filtered['system_cpu_usage'], - system_storage_usage=filtered['system_storage_usage'], - system_ram_usage=filtered['system_ram_usage'], - system_is_down=filtered['system_is_down'], - ) - - self._create_and_start_alerter_process( - system_alerts_config, parent_id, chain) - self._systems_alerts_configs[parent_id] = system_alerts_config - except MessageWasNotDeliveredException as e: - # If the internal alert cannot be delivered, requeue the config - # for re-processing. - self.logger.error("Error when processing %s", sent_configs) - self.logger.exception(e) - self.rabbitmq.basic_nack(method.delivery_tag) - return - except Exception as e: - # Otherwise log and reject the message - self.logger.error("Error when processing %s", sent_configs) - self.logger.exception(e) - - self.rabbitmq.basic_ack(method.delivery_tag, False) - def _process_ping( self, ch: BlockingChannel, method: pika.spec.Basic.Deliver, properties: pika.spec.BasicProperties, body: bytes) -> None: @@ -222,22 +124,18 @@ def _process_ping( heartbeat['component_name'] = self.name heartbeat['running_processes'] = [] heartbeat['dead_processes'] = [] - for parent_id, process_details in \ - self.parent_id_process_dict.items(): - process = process_details['process'] - component_name = process_details['component_name'] + + for alerter, process in self.alerter_process_dict.items(): if process.is_alive(): - heartbeat['running_processes'].append(component_name) + heartbeat['running_processes'].append(alerter) else: - heartbeat['dead_processes'].append(component_name) + heartbeat['dead_processes'].append(alerter) process.join() # Just in case, to release resources - # Restart dead process - chain = process_details['chain'] - system_alerts_config = self.systems_alerts_configs[ - parent_id] - self._create_and_start_alerter_process( - system_alerts_config, parent_id, chain) + # Restart dead process + if len(heartbeat['dead_processes']) > 0: + self._create_and_start_alerter_process() + heartbeat['timestamp'] = datetime.now().timestamp() except Exception as e: # If we encounter an error during processing log the error and @@ -257,11 +155,104 @@ def _process_ping( # For any other exception raise it. raise e + def _create_and_start_alerter_process(self) -> None: + """ + Start the System Alerters in a separate process if they are not yet + started, or they are not alive. This must be done in case of a restart + of the manager. + """ + for alerter_name, alerter_details in \ + self.configs_processor_helper.items(): + if (alerter_name not in self.alerter_process_dict or + not self.alerter_process_dict[alerter_name].is_alive()): + """ + We must clear out all the metrics which are found in Redis. + Sending this alert to the alert router and then the data store + will achieve this. This is sent on startup of the manager + and if the alerter process is deemed to be dead. + """ + alert = ComponentResetAlert( + alerter_name, datetime.now().timestamp(), + alerter_details['alerterClass'].__name__) + self._push_latest_data_to_queue_and_send( + alert.alert_data, alerter_details['routing_key']) + + """ + Start the Alerter process with the factory being updated by + this manager. This factory should hold all the configurations, + if any. + """ + log_and_print("Attempting to start the {}.".format( + alerter_name), self.logger) + alerter_process = Process(target=alerter_details['starter'], + args=(alerter_details['factory'],)) + alerter_process.daemon = True + alerter_process.start() + + self._alerter_process_dict[alerter_name] = alerter_process + + def _process_configs( + self, ch: BlockingChannel, method: pika.spec.Basic.Deliver, + properties: pika.spec.BasicProperties, body: bytes) -> None: + sent_configs = json.loads(body) + + self.logger.debug("Received configs %s", sent_configs) + + if 'DEFAULT' in sent_configs: + del sent_configs['DEFAULT'] + + if method.routing_key == ALERTS_CONFIGS_ROUTING_KEY_GEN: + chain = 'general' + else: + parsed_routing_key = method.routing_key.split('.') + chain = parsed_routing_key[1] + ' ' + parsed_routing_key[2] + + try: + """ + If we received a config then we must add it to the config + factory, which stores all the System alert configurations. If the + received dictionary is empty then delete the configuration which is + saved under the routing_key. + + We also check if the configuration has been updated, if it has then + the metrics in Redis need to be reset. + """ + if bool(sent_configs): + for alerter_name, alerter_details in \ + self.configs_processor_helper.items(): + configs_factory = alerter_details['factory'] + alerter_class = alerter_details['alerterClass'] + configs_factory.add_new_config(chain, sent_configs) + parent_id = configs_factory.get_parent_id(chain) + alert = ComponentResetAlert( + alerter_name, datetime.now().timestamp(), + alerter_class.__name__, parent_id, chain + ) + self._push_latest_data_to_queue_and_send( + alert.alert_data, alerter_details['routing_key']) + else: + for _, alerter_details in self.configs_processor_helper.items(): + configs_factory = alerter_details['factory'] + configs_factory.remove_config(chain) + + except Exception as e: + self.logger.error("Error when processing %s", sent_configs) + self.logger.exception(e) + + self.rabbitmq.basic_ack(method.delivery_tag, False) + def start(self) -> None: log_and_print("{} started.".format(self), self.logger) self._initialise_rabbitmq() while True: try: + # Empty the queue so that on restart we don't send multiple + # reset alerts. We are not sending the alert before starting + # a component, so that should be enough. + if not self.publishing_queue.empty(): + self.publishing_queue.queue.clear() + + self._create_and_start_alerter_process() self._listen_for_data() except (pika.exceptions.AMQPConnectionError, pika.exceptions.AMQPChannelError) as e: @@ -273,30 +264,27 @@ def start(self) -> None: self.logger.exception(e) raise e - # If termination signals are received, terminate all child process and - # close the connection with rabbit mq before exiting + # If termination signals are received, terminate all child process and exit def _on_terminate(self, signum: int, stack: FrameType) -> None: - log_and_print( - "{} is terminating. Connections with RabbitMQ will be closed, and " - "any running system alerters will be stopped gracefully. " - "Afterwards the {} process will exit.".format(self, self), - self.logger) - self.disconnect_from_rabbit() - - for _, process_details in self.parent_id_process_dict.items(): - log_and_print("Terminating the alerter process of {}".format( - process_details['chain']), self.logger) - process = process_details['process'] + log_and_print("{} is terminating. Connections with RabbitMQ will be " + "closed, and the System alerters will be stopped " + "gracefully. Afterwards the {} process will " + "exit.".format(self, self), self.logger) + + for alerter, process in self.alerter_process_dict.items(): + log_and_print("Terminating the process of {}".format(alerter), + self.logger) process.terminate() process.join() - + self.disconnect_from_rabbit() log_and_print("{} terminated.".format(self), self.logger) sys.exit() - def _push_latest_data_to_queue_and_send(self, alert: Dict) -> None: + def _push_latest_data_to_queue_and_send(self, alert: Dict, + routing_key: str) -> None: self._push_to_queue( data=copy.deepcopy(alert), exchange=ALERT_EXCHANGE, - routing_key=SYSTEM_ALERT_ROUTING_KEY, + routing_key=routing_key, properties=pika.BasicProperties(delivery_mode=2), mandatory=True ) self._send_data() diff --git a/alerter/src/configs/alerts/node/chainlink.py b/alerter/src/configs/alerts/node/chainlink.py index 96d36c326..849ccd278 100644 --- a/alerter/src/configs/alerts/node/chainlink.py +++ b/alerter/src/configs/alerts/node/chainlink.py @@ -8,8 +8,8 @@ def __init__(self, parent_id: str, head_tracker_current_head: Dict, process_start_time_seconds: Dict, tx_manager_gas_bump_exceeds_limit_total: Dict, unconfirmed_transactions: Dict, - run_status_update_total: Dict, eth_balance_amount: Dict, - eth_balance_amount_increase: Dict, node_is_down: Dict) -> None: + run_status_update_total: Dict, balance_amount: Dict, + balance_amount_increase: Dict, node_is_down: Dict) -> None: self._parent_id = parent_id self._head_tracker_current_head = head_tracker_current_head self._head_tracker_heads_received_total = \ @@ -20,8 +20,8 @@ def __init__(self, parent_id: str, head_tracker_current_head: Dict, tx_manager_gas_bump_exceeds_limit_total self._unconfirmed_transactions = unconfirmed_transactions self._run_status_update_total = run_status_update_total - self._eth_balance_amount = eth_balance_amount - self._eth_balance_amount_increase = eth_balance_amount_increase + self._balance_amount = balance_amount + self._balance_amount_increase = balance_amount_increase self._node_is_down = node_is_down def __eq__(self, other: Any) -> bool: @@ -60,12 +60,12 @@ def run_status_update_total(self) -> Dict: return self._run_status_update_total @property - def eth_balance_amount(self) -> Dict: - return self._eth_balance_amount + def balance_amount(self) -> Dict: + return self._balance_amount @property - def eth_balance_amount_increase(self) -> Dict: - return self._eth_balance_amount_increase + def balance_amount_increase(self) -> Dict: + return self._balance_amount_increase @property def node_is_down(self) -> Dict: diff --git a/alerter/src/configs/alerts/system.py b/alerter/src/configs/alerts/system.py index 3ee257bba..393342ae1 100644 --- a/alerter/src/configs/alerts/system.py +++ b/alerter/src/configs/alerts/system.py @@ -1,4 +1,4 @@ -from typing import Dict +from typing import Dict, Any class SystemAlertsConfig: @@ -15,6 +15,9 @@ def __init__(self, parent_id: str, self._system_ram_usage = system_ram_usage self._system_is_down = system_is_down + def __eq__(self, other: Any) -> bool: + return self.__dict__ == other.__dict__ + @property def parent_id(self) -> str: return self._parent_id diff --git a/alerter/src/configs/factory/alerts/chainlink_alerts.py b/alerter/src/configs/factory/alerts/chainlink_alerts.py index abcb6469d..aa78e64da 100644 --- a/alerter/src/configs/factory/alerts/chainlink_alerts.py +++ b/alerter/src/configs/factory/alerts/chainlink_alerts.py @@ -106,9 +106,8 @@ def add_new_config(self, chain_name: str, sent_configs: Dict) -> None: unconfirmed_transactions=filtered[ 'unconfirmed_transactions'], run_status_update_total=filtered['run_status_update_total'], - eth_balance_amount=filtered['eth_balance_amount'], - eth_balance_amount_increase=filtered[ - 'eth_balance_amount_increase'], + balance_amount=filtered['balance_amount'], + balance_amount_increase=filtered['balance_amount_increase'], node_is_down=filtered['node_is_down'], ) diff --git a/alerter/src/configs/factory/alerts/system_alerts.py b/alerter/src/configs/factory/alerts/system_alerts.py new file mode 100644 index 000000000..d1b4fed63 --- /dev/null +++ b/alerter/src/configs/factory/alerts/system_alerts.py @@ -0,0 +1,85 @@ +import copy +from typing import Optional, Dict + +from src.configs.alerts.system import SystemAlertsConfig +from src.configs.factory.configs_factory import ConfigsFactory +from src.utils.exceptions import ParentIdsMissMatchInAlertsConfiguration + + +class SystemAlertsConfigsFactory(ConfigsFactory): + """ + This class manages the systems alerts configs. The configs are indexed by + the chain name, and it is expected that each chain has exactly one alerts + config. + """ + + def __init__(self) -> None: + super().__init__() + + def add_new_config(self, chain_name: str, sent_configs: Dict) -> None: + # Check if all the parent_ids in the received configuration are the + # same, if not there is some misconfiguration + parent_ids = { + configuration['parent_id'] + for _, configuration in sent_configs.items() + } + if len(parent_ids) != 1: + raise ParentIdsMissMatchInAlertsConfiguration( + "{}: add_new_config".format(self)) + + filtered = { + config['name']: copy.deepcopy(config) + for _, config in sent_configs.items() + } + + system_alerts_config = SystemAlertsConfig( + parent_id=parent_ids.pop(), + open_file_descriptors=filtered['open_file_descriptors'], + system_cpu_usage=filtered['system_cpu_usage'], + system_storage_usage=filtered['system_storage_usage'], + system_ram_usage=filtered['system_ram_usage'], + system_is_down=filtered['system_is_down'] + ) + + self._configs[chain_name] = system_alerts_config + + def remove_config(self, chain_name: str) -> None: + if chain_name in self.configs: + del self._configs[chain_name] + + def config_exists(self, chain_name: str) -> bool: + """ + This function returns True if a configuration exists for a chain name. + :param chain_name: The name of the chain in question + :return: True if config exists + : False otherwise + """ + return (chain_name in self.configs + and type(self.configs[chain_name]) == SystemAlertsConfig) + + def get_parent_id(self, chain_name: str) -> Optional[str]: + """ + This function returns the parent_id of a chain whose name is chain_name. + :param chain_name: The name of the chain in question + :return: The parent_id of the chain if chain_name in self.configs + : None otherwise + """ + if self.config_exists(chain_name): + return self.configs[chain_name].parent_id + else: + return None + + def get_chain_name(self, parent_id: str) -> Optional[str]: + """ + This function returns the chain name associated with the id. + :param parent_id: The id of the chain in question + :return: The name of the chain if there is a config having the given + : parent_id + : None otherwise + """ + for chain_name, config in self.configs.items(): + if (type(config) == SystemAlertsConfig and + config.parent_id == parent_id): + return chain_name + + return None diff --git a/alerter/src/data_store/redis/store_keys.py b/alerter/src/data_store/redis/store_keys.py index 74a3d0a74..91fba38f7 100644 --- a/alerter/src/data_store/redis/store_keys.py +++ b/alerter/src/data_store/redis/store_keys.py @@ -31,7 +31,7 @@ _key_cl_node_no_of_unconfirmed_txs = 'cl7' _key_cl_node_total_errored_job_runs = 'cl8' _key_cl_node_current_gas_price_info = 'cl9' -_key_cl_node_eth_balance_info = 'cl10' +_key_cl_node_balance_info = 'cl10' _key_cl_node_went_down_at_prometheus = 'cl11' _key_cl_node_last_prometheus_source_used = 'cl12' _key_cl_node_last_monitored_prometheus = 'cl13' @@ -117,8 +117,8 @@ _key_alert_cl_tx_manager_gas_bump_exceeds_limit_total = 'alert_cl_node5' _key_alert_cl_unconfirmed_transactions = 'alert_cl_node6' _key_alert_cl_run_status_update_total = 'alert_cl_node7' -_key_alert_cl_eth_balance_amount = 'alert_cl_node8' -_key_alert_cl_eth_balance_amount_increase = 'alert_cl_node9' +_key_alert_cl_balance_amount = 'alert_cl_node8' +_key_alert_cl_balance_amount_increase = 'alert_cl_node9' _key_alert_cl_invalid_url = 'alert_cl_node10' _key_alert_cl_metric_not_found = 'alert_cl_node11' _key_alert_cl_node_is_down = 'alert_cl_node12' @@ -293,8 +293,8 @@ def get_cl_node_current_gas_price_info(cl_node_id: str) -> str: return Keys._as_prefix(_key_cl_node_current_gas_price_info) + cl_node_id @staticmethod - def get_cl_node_eth_balance_info(cl_node_id: str) -> str: - return Keys._as_prefix(_key_cl_node_eth_balance_info) + cl_node_id + def get_cl_node_balance_info(cl_node_id: str) -> str: + return Keys._as_prefix(_key_cl_node_balance_info) + cl_node_id @staticmethod def get_cl_node_went_down_at_prometheus(cl_node_id: str) -> str: @@ -566,13 +566,13 @@ def get_alert_cl_invalid_url(origin_id: str) -> str: return Keys._as_prefix(_key_alert_cl_invalid_url) + origin_id @staticmethod - def get_alert_cl_eth_balance_amount_increase(origin_id: str) -> str: + def get_alert_cl_balance_amount_increase(origin_id: str) -> str: return Keys._as_prefix( - _key_alert_cl_eth_balance_amount_increase) + origin_id + _key_alert_cl_balance_amount_increase) + origin_id @staticmethod - def get_alert_cl_eth_balance_amount(origin_id: str) -> str: - return Keys._as_prefix(_key_alert_cl_eth_balance_amount) + origin_id + def get_alert_cl_balance_amount(origin_id: str) -> str: + return Keys._as_prefix(_key_alert_cl_balance_amount) + origin_id @staticmethod def get_alert_cl_run_status_update_total(origin_id: str) -> str: diff --git a/alerter/src/data_store/stores/node/chainlink.py b/alerter/src/data_store/stores/node/chainlink.py index d0f5c4e8e..c0cf092b0 100644 --- a/alerter/src/data_store/stores/node/chainlink.py +++ b/alerter/src/data_store/stores/node/chainlink.py @@ -127,7 +127,7 @@ def _process_redis_prometheus_result_store(self, data: Dict) -> None: "_max_pending_tx_delay=%s, _process_start_time_seconds=%s, " "_total_gas_bumps=%s, _total_gas_bumps_exceeds_limit=%s, " "_no_of_unconfirmed_txs=%s, _total_errored_job_runs=%s, " - "_current_gas_price_info=%s, _eth_balance_info=%s, " + "_current_gas_price_info=%s, _balance_info=%s, " "_last_monitored_prometheus=%s, _last_prometheus_source_used=%s, " "_went_down_at_prometheus=%s", node_name, metrics['current_height'], metrics['total_block_headers_received'], @@ -135,7 +135,7 @@ def _process_redis_prometheus_result_store(self, data: Dict) -> None: metrics['process_start_time_seconds'], metrics['total_gas_bumps'], metrics['total_gas_bumps_exceeds_limit'], metrics['no_of_unconfirmed_txs'], metrics['total_errored_job_runs'], - metrics['current_gas_price_info'], metrics['eth_balance_info'], + metrics['current_gas_price_info'], metrics['balance_info'], meta_data['last_monitored'], meta_data['last_source_used'], metrics['went_down_at']) @@ -161,8 +161,8 @@ def _process_redis_prometheus_result_store(self, data: Dict) -> None: Keys.get_cl_node_current_gas_price_info(node_id): 'None' if metrics['current_gas_price_info'] is None else json.dumps(metrics['current_gas_price_info']), - Keys.get_cl_node_eth_balance_info(node_id): - json.dumps(metrics['eth_balance_info']), + Keys.get_cl_node_balance_info(node_id): + json.dumps(metrics['balance_info']), Keys.get_cl_node_last_prometheus_source_used(node_id): str(meta_data['last_source_used']), Keys.get_cl_node_last_monitored_prometheus(node_id): @@ -258,8 +258,8 @@ def _process_mongo_prometheus_result_store(self, data: Dict) -> None: 'current_gas_price_info': 'None' if metrics['current_gas_price_info'] is None else json.dumps(metrics['current_gas_price_info']), - 'eth_balance_info': - json.dumps(metrics['eth_balance_info']), + 'balance_info': + json.dumps(metrics['balance_info']), 'went_down_at_prometheus': str(metrics['went_down_at']), 'last_prometheus_source_used': str(meta_data['last_source_used']), diff --git a/alerter/src/data_store/stores/system.py b/alerter/src/data_store/stores/system.py index 54afb3721..aa8a81c46 100644 --- a/alerter/src/data_store/stores/system.py +++ b/alerter/src/data_store/stores/system.py @@ -10,8 +10,8 @@ from src.data_store.stores.store import Store from src.message_broker.rabbitmq.rabbitmq_api import RabbitMQApi from src.utils.constants.rabbitmq import (STORE_EXCHANGE, HEALTH_CHECK_EXCHANGE, - SYSTEM_STORE_INPUT_QUEUE_NAME, - SYSTEM_STORE_INPUT_ROUTING_KEY, TOPIC) + SYSTEM_STORE_INPUT_QUEUE_NAME, TOPIC, + SYSTEM_TRANSFORMED_DATA_ROUTING_KEY) from src.utils.exceptions import (ReceivedUnexpectedDataException, SystemIsDownException, MessageWasNotDeliveredException) @@ -47,9 +47,9 @@ def _initialise_rabbitmq(self) -> None: self.rabbitmq.queue_declare(SYSTEM_STORE_INPUT_QUEUE_NAME, passive=False, durable=True, exclusive=False, auto_delete=False) - self.rabbitmq.queue_bind(queue=SYSTEM_STORE_INPUT_QUEUE_NAME, - exchange=STORE_EXCHANGE, - routing_key=SYSTEM_STORE_INPUT_ROUTING_KEY) + self.rabbitmq.queue_bind( + queue=SYSTEM_STORE_INPUT_QUEUE_NAME, exchange=STORE_EXCHANGE, + routing_key=SYSTEM_TRANSFORMED_DATA_ROUTING_KEY) # Set producing configuration for heartbeat self.logger.info("Setting delivery confirmation on RabbitMQ channel") diff --git a/alerter/src/data_transformers/node/chainlink.py b/alerter/src/data_transformers/node/chainlink.py index a53c418a9..6348a5aeb 100644 --- a/alerter/src/data_transformers/node/chainlink.py +++ b/alerter/src/data_transformers/node/chainlink.py @@ -158,14 +158,14 @@ def _load_dict_state(self, cl_node: Monitorable) -> None: cl_node.set_current_gas_price_info(current_gas_price_info['percentile'], current_gas_price_info['price']) - # Load eth_balance_info from Redis - state_eth_balance_info = cl_node.eth_balance_info - redis_eth_balance_info = self.redis.hget( - redis_hash, Keys.get_cl_node_eth_balance_info(cl_node_id), - bytes(json.dumps(state_eth_balance_info), 'utf-8')) - eth_balance_info = {} if redis_eth_balance_info is None \ - else json.loads(redis_eth_balance_info.decode("utf-8")) - cl_node.set_eth_balance_info(eth_balance_info) + # Load balance_info from Redis + state_balance_info = cl_node.balance_info + redis_balance_info = self.redis.hget( + redis_hash, Keys.get_cl_node_balance_info(cl_node_id), + bytes(json.dumps(state_balance_info), 'utf-8')) + balance_info = {} if redis_balance_info is None \ + else json.loads(redis_balance_info.decode("utf-8")) + cl_node.set_balance_info(balance_info) def load_state(self, cl_node: Monitorable) -> Monitorable: self.logger.debug("Loading the state of %s from Redis", cl_node) @@ -181,14 +181,14 @@ def load_state(self, cl_node: Monitorable) -> Monitorable: "_max_pending_tx_delay=%s, _process_start_time_seconds=%s, " "_total_gas_bumps=%s, _total_gas_bumps_exceeds_limit=%s, " "_no_of_unconfirmed_txs=%s, _total_errored_job_runs=%s, " - "_current_gas_price_info=%s, _eth_balance_info=%s, " + "_current_gas_price_info=%s, _balance_info=%s, " "_last_monitored_prometheus=%s, _last_prometheus_source_used=%s, " "_went_down_at_prometheus=%s", cl_node, cl_node.current_height, cl_node.total_block_headers_received, cl_node.max_pending_tx_delay, cl_node.process_start_time_seconds, cl_node.total_gas_bumps, cl_node.total_gas_bumps_exceeds_limit, cl_node.no_of_unconfirmed_txs, cl_node.total_errored_job_runs, - cl_node.current_gas_price_info, cl_node.eth_balance_info, + cl_node.current_gas_price_info, cl_node.balance_info, cl_node.last_monitored_prometheus, cl_node.last_prometheus_source_used, cl_node.went_down_at_prometheus) @@ -424,27 +424,30 @@ def _transform_prometheus_data(self, prometheus_data: Dict) -> Dict: 'percentile'] = convert_to_float( str_percentile.replace('%', ''), None) - # Add latest_usage to the eth_balance_info if not empty - if node_metrics['eth_balance']: - eth_address = node_metrics['eth_balance']['address'] - new_balance = node_metrics['eth_balance']['balance'] - if node.eth_balance_info and \ - eth_address == node.eth_balance_info['address']: - previous_balance = node.eth_balance_info['balance'] - latest_usage = previous_balance - new_balance if \ - previous_balance > new_balance else 0.0 + # Add latest_usage to the balance_info if not empty + if node_metrics['balance']: + address = node_metrics['balance']['address'] + new_balance = node_metrics['balance']['balance'] + symbol = node_metrics['balance']['symbol'] + if (node.balance_info and + address == node.balance_info['address']): + previous_balance = node.balance_info['balance'] + latest_usage = previous_balance - new_balance if ( + previous_balance > new_balance) else 0.0 new_info_dict = { 'balance': new_balance, 'latest_usage': latest_usage, - 'address': eth_address, + 'address': address, + 'symbol': symbol, } else: new_info_dict = { 'balance': new_balance, 'latest_usage': 0.0, - 'address': eth_address, + 'address': address, + 'symbol': symbol, } - td_node_metrics['eth_balance_info'] = new_info_dict + td_node_metrics['balance_info'] = new_info_dict # Transform the meta_data by deleting the monitor_name and # changing the time key to last_monitored key diff --git a/alerter/src/data_transformers/system.py b/alerter/src/data_transformers/system.py index feaa09e85..8f976dc3e 100644 --- a/alerter/src/data_transformers/system.py +++ b/alerter/src/data_transformers/system.py @@ -15,7 +15,7 @@ from src.utils.constants.rabbitmq import ( ALERT_EXCHANGE, STORE_EXCHANGE, RAW_DATA_EXCHANGE, HEALTH_CHECK_EXCHANGE, SYSTEM_DT_INPUT_QUEUE_NAME, SYSTEM_RAW_DATA_ROUTING_KEY, - SYSTEM_TRANSFORMED_DATA_ROUTING_KEY_TEMPLATE, TOPIC) + SYSTEM_TRANSFORMED_DATA_ROUTING_KEY, TOPIC) from src.utils.exceptions import (ReceivedUnexpectedDataException, SystemIsDownException, MessageWasNotDeliveredException) @@ -41,8 +41,7 @@ def _initialise_rabbitmq(self) -> None: False, False) self.logger.info("Creating queue '%s'", SYSTEM_DT_INPUT_QUEUE_NAME) self.rabbitmq.queue_declare(SYSTEM_DT_INPUT_QUEUE_NAME, False, True, - False, - False) + False, False) self.logger.info("Binding queue '%s' to exchange '%s' with routing " "key '%s'", SYSTEM_DT_INPUT_QUEUE_NAME, RAW_DATA_EXCHANGE, @@ -545,22 +544,12 @@ def _transform_data(self, data: Dict) -> Tuple[Dict, Dict, Dict]: def _place_latest_data_on_queue(self, transformed_data: Dict, data_for_alerting: Dict, data_for_saving: Dict) -> None: - # Compute the routing key for alerting. The routing key will be in - # the format `alerter.system.parent_id - response_index_key = 'result' if 'result' in transformed_data \ - else 'error' - meta_data = transformed_data[response_index_key]['meta_data'] - system_parent_id = meta_data['system_parent_id'] - alerting_routing_key = \ - SYSTEM_TRANSFORMED_DATA_ROUTING_KEY_TEMPLATE.format( - system_parent_id) - self._push_to_queue(data_for_alerting, ALERT_EXCHANGE, - alerting_routing_key, + SYSTEM_TRANSFORMED_DATA_ROUTING_KEY, pika.BasicProperties(delivery_mode=2), True) self._push_to_queue(data_for_saving, STORE_EXCHANGE, - alerting_routing_key, + SYSTEM_TRANSFORMED_DATA_ROUTING_KEY, pika.BasicProperties(delivery_mode=2), True) def _process_raw_data(self, ch: BlockingChannel, diff --git a/alerter/src/monitorables/nodes/chainlink_node.py b/alerter/src/monitorables/nodes/chainlink_node.py index 37e4f2c4b..1f49d55e1 100644 --- a/alerter/src/monitorables/nodes/chainlink_node.py +++ b/alerter/src/monitorables/nodes/chainlink_node.py @@ -25,7 +25,7 @@ def __init__(self, node_name: str, node_id: str, parent_id: str) -> None: 'percentile': None, 'price': None, } - self._eth_balance_info = {} + self._balance_info = {} # This variable stores the url of the source used to get prometheus node # data. Note that this had to be done because multiple prometheus @@ -81,8 +81,8 @@ def current_gas_price_info(self) -> Dict[str, Optional[float]]: return self._current_gas_price_info @property - def eth_balance_info(self) -> Dict[str, Union[str, float]]: - return self._eth_balance_info + def balance_info(self) -> Dict[str, Union[str, float]]: + return self._balance_info @property def last_prometheus_source_used(self) -> Optional[str]: @@ -123,7 +123,7 @@ def get_dict_prometheus_metric_attributes() -> List[str]: :return: A list of all variable names representing dict prometheus : metrics. """ - return ['current_gas_price_info', 'eth_balance_info'] + return ['current_gas_price_info', 'balance_info'] @staticmethod def get_str_prometheus_metric_attributes() -> List[str]: @@ -261,11 +261,11 @@ def set_current_gas_price_info(self, new_percentile: Optional[float], self._current_gas_price_info['price'] = new_price @staticmethod - def _new_eth_balance_info_valid(new_eth_balance_info: Dict) -> bool: + def _new_balance_info_valid(new_balance_info: Dict) -> bool: """ - This method checks that the new eth_balance_info dict obeys the required + This method checks that the new balance_info dict obeys the required schema. - :param new_eth_balance_info: The dict to check + :param new_balance_info: The dict to check :return: True if the dict obeys the required schema : False otherwise """ @@ -273,22 +273,23 @@ def _new_eth_balance_info_valid(new_eth_balance_info: Dict) -> bool: 'address': str, 'balance': float, 'latest_usage': float, + 'symbol': str, }, {})) - return schema.is_valid(new_eth_balance_info) + return schema.is_valid(new_balance_info) - def set_eth_balance_info( - self, new_eth_balance_info: Dict[str, Union[str, float]]) -> None: + def set_balance_info( + self, new_balance_info: Dict[str, Union[str, float]]) -> None: """ - This method sets the new_eth_balance_info. It first checks that the new + This method sets the new_balance_info. It first checks that the new dict obeys the required schema. If not, an InvalidDictSchemaException is raised. - :param new_eth_balance_info: The new eth_balance_info to store. + :param new_balance_info: The new balance_info to store. :return: None """"" - if self._new_eth_balance_info_valid(new_eth_balance_info): - self._eth_balance_info = new_eth_balance_info + if self._new_balance_info_valid(new_balance_info): + self._balance_info = new_balance_info else: - raise InvalidDictSchemaException('new_eth_balance_info') + raise InvalidDictSchemaException('new_balance_info') def set_last_prometheus_source_used( self, new_last_prometheus_source_used: Optional[str]) -> None: @@ -313,6 +314,6 @@ def reset(self) -> None: self.set_no_of_unconfirmed_txs(None) self.set_total_errored_job_runs(None) self.set_current_gas_price_info(None, None) - self.set_eth_balance_info({}) + self.set_balance_info({}) self.set_last_prometheus_source_used(None) self.set_last_monitored_prometheus(None) diff --git a/alerter/src/monitors/contracts/chainlink.py b/alerter/src/monitors/contracts/chainlink.py index d856dfdd1..09f8616b2 100644 --- a/alerter/src/monitors/contracts/chainlink.py +++ b/alerter/src/monitors/contracts/chainlink.py @@ -66,9 +66,9 @@ def __init__(self, monitor_name: str, weiwatchers_url: str, w3_interface.middleware_onion.inject(geth_poa_middleware, layer=0) self._evm_node_w3_interface[evm_node_url] = w3_interface - # This dict stores the eth address of a chainlink node indexed by the - # node id. The eth address is obtained from prometheus. - self._node_eth_address = {} + # This dict stores the address of a chainlink node indexed by the + # node id. This address is obtained from prometheus. + self._node_address = {} # This list stores a list of chain contracts data obtained from the wei # watchers link @@ -96,7 +96,7 @@ def __init__(self, monitor_name: str, weiwatchers_url: str, # Data retrieval limiters self._wei_watchers_retrieval_limiter = TimedTaskLimiter( timedelta(seconds=float(_WEI_WATCHERS_RETRIEVAL_TIME_PERIOD))) - self._eth_address_retrieval_limiter = TimedTaskLimiter( + self._address_retrieval_limiter = TimedTaskLimiter( timedelta(seconds=float(_PROMETHEUS_RETRIEVAL_TIME_PERIOD))) @property @@ -112,8 +112,8 @@ def contracts_url(self) -> str: return self._contracts_url @property - def node_eth_address(self) -> Dict[str, str]: - return self._node_eth_address + def node_address(self) -> Dict[str, str]: + return self._node_address @property def contracts_data(self) -> List[Dict]: @@ -136,8 +136,8 @@ def wei_watchers_retrieval_limiter(self) -> TimedTaskLimiter: return self._wei_watchers_retrieval_limiter @property - def eth_address_retrieval_limiter(self) -> TimedTaskLimiter: - return self._eth_address_retrieval_limiter + def address_retrieval_limiter(self) -> TimedTaskLimiter: + return self._address_retrieval_limiter def _get_chain_contracts(self) -> List[Dict]: """ @@ -154,21 +154,21 @@ def _store_chain_contracts(self, contracts_data: List[Dict]) -> None: """ self._contracts_data = contracts_data - def _get_nodes_eth_address(self) -> Tuple[Dict, bool]: + def _get_nodes_address(self) -> Tuple[Dict, bool]: """ - This function attempts to get all the Ethereum addresses associated with - each node from the prometheus endpoints. For each node it attempts to - connect with the online source to get the eth address, however if the + This function attempts to get all the addresses associated with each + node from the prometheus endpoints. For each node it attempts to + connect with the online source to get the address, however if the required data cannot be obtained from any source, the node is not added to the output dict, and the second element in the tuple is set to True indicating that the dict does not contain all node ids. :return: A tuple with the following structure: - ({ node_id: node_eth_address }, bool) + ({ node_id: node_address }, bool) """ metrics_to_retrieve = { 'eth_balance': 'strict', } - node_eth_address = {} + node_address = {} error_occurred = False for node_config in self.node_configs: for prom_url in node_config.node_prometheus_urls: @@ -178,8 +178,8 @@ def _get_nodes_eth_address(self) -> Tuple[Dict, bool]: verify=False) for _, data_subset in enumerate(metrics['eth_balance']): if "account" in json.loads(data_subset): - eth_address = json.loads(data_subset)['account'] - node_eth_address[node_config.node_id] = eth_address + address = json.loads(data_subset)['account'] + node_address[node_config.node_id] = address break break except (ReqConnectionError, ReadTimeout, InvalidURL, @@ -198,22 +198,21 @@ def _get_nodes_eth_address(self) -> Tuple[Dict, bool]: self.logger.exception(e) break - # If no ethereum address was added for a node, then an error has - # occurred - if node_config.node_id not in node_eth_address: + # If no address was added for a node, then an error has occurred + if node_config.node_id not in node_address: error_occurred = True - return node_eth_address, error_occurred + return node_address, error_occurred - def _store_nodes_eth_addresses(self, node_eth_address: Dict) -> None: + def _store_nodes_addresses(self, node_address: Dict) -> None: """ - This function stores the node's associated ethereum addresses obtained - from prometheus in the state - :param node_eth_address: A dict associating a node's ID to it's ethereum - : address obtained from prometheus + This function stores the node's associated addresses obtained from + prometheus in the state + :param node_address: A dict associating a node's ID to its address + : obtained from prometheus. :return: None """ - self._node_eth_address = node_eth_address + self._node_address = node_address def _select_node(self) -> Optional[str]: """ @@ -244,9 +243,8 @@ def _filter_contracts_by_node(self, selected_node: str) -> Dict: """ w3_interface = self.evm_node_w3_interface[selected_node] node_contracts = {} - for node_id, eth_address in self._node_eth_address.items(): - transformed_eth_address = w3_interface.toChecksumAddress( - eth_address) + for node_id, address in self._node_address.items(): + transformed_address = w3_interface.toChecksumAddress(address) v3_participating_contracts = [] v4_participating_contracts = [] for contract_data in self._contracts_data: @@ -257,14 +255,14 @@ def _filter_contracts_by_node(self, selected_node: str) -> Dict: aggregator_contract = w3_interface.eth.contract( address=aggregator_address, abi=V3_AGGREGATOR) oracles = aggregator_contract.functions.getOracles().call() - if transformed_eth_address in oracles: + if transformed_address in oracles: v3_participating_contracts.append(proxy_address) elif contract_version == 4: aggregator_contract = w3_interface.eth.contract( address=aggregator_address, abi=V4_AGGREGATOR) transmitters = ( aggregator_contract.functions.transmitters().call()) - if transformed_eth_address in transmitters: + if transformed_address in transmitters: v4_participating_contracts.append(proxy_address) node_contracts[node_id] = {} @@ -281,14 +279,14 @@ def _store_node_contracts(self, node_contracts: Dict) -> None: """ self._node_contracts = node_contracts - def _get_v3_data(self, w3_interface: Web3, node_eth_address: str, + def _get_v3_data(self, w3_interface: Web3, node_address: str, node_id: str) -> Dict: """ This function attempts to retrieve the v3 contract metrics for a node using an evm node as data source. :param w3_interface: The web3 interface used to get the data - :param node_eth_address: The ethereum address of the node the metrics - : are associated with. + :param node_address: The address of the node the metrics + : are associated with. :param node_id: The id of the node the metrics are associated with. :return: A dict with the following structure: { @@ -339,8 +337,7 @@ def _get_v3_data(self, w3_interface: Web3, node_eth_address: str, description = proxy_contract.functions.description().call() aggregator_contract = w3_interface.eth.contract( address=aggregator_address, abi=V3_AGGREGATOR) - transformed_eth_address = w3_interface.toChecksumAddress( - node_eth_address) + transformed_address = w3_interface.toChecksumAddress(node_address) # Get all SubmissionReceived events related to the node in question # from the last block height not monitored until the current block @@ -359,7 +356,7 @@ def _get_v3_data(self, w3_interface: Web3, node_eth_address: str, aggregator_contract.events.SubmissionReceived.createFilter( fromBlock=first_block_to_monitor, toBlock=current_block_height, - argument_filters={'oracle': transformed_eth_address}) + argument_filters={'oracle': transformed_address}) events = event_filter.get_all_entries() latest_round_data = ( aggregator_contract.functions.latestRoundData().call()) @@ -375,7 +372,7 @@ def _get_v3_data(self, w3_interface: Web3, node_eth_address: str, 'answeredInRound': latest_round_data[4], 'withdrawablePayment': aggregator_contract.functions.withdrawablePayment( - transformed_eth_address).call(), + transformed_address).call(), 'historicalRounds': [] } @@ -439,14 +436,14 @@ def _get_v3_data(self, w3_interface: Web3, node_eth_address: str, return data - def _get_v4_data(self, w3_interface: Web3, node_eth_address: str, + def _get_v4_data(self, w3_interface: Web3, node_address: str, node_id: str) -> Dict: """ This function attempts to retrieve the v4 contract metrics for a node using an evm node as data source. :param w3_interface: The web3 interface used to get the data - :param node_eth_address: The ethereum address of the node the metrics - : are associated with. + :param node_address: The address of the node the metrics are associated + : with. :param node_id: The id of the node the metrics are associated with. :return: A dict with the following structure: { @@ -496,8 +493,7 @@ def _get_v4_data(self, w3_interface: Web3, node_eth_address: str, description = proxy_contract.functions.description().call() aggregator_contract = w3_interface.eth.contract( address=aggregator_address, abi=V4_AGGREGATOR) - transformed_eth_address = w3_interface.toChecksumAddress( - node_eth_address) + transformed_address = w3_interface.toChecksumAddress(node_address) # Get all NewTransmission events related to the node in question # from the last block height not monitored until the current block @@ -522,8 +518,7 @@ def _get_v4_data(self, w3_interface: Web3, node_eth_address: str, transmitters = aggregator_contract.functions.transmitters().call() try: - node_transmitter_index = transmitters.index( - transformed_eth_address) + node_transmitter_index = transmitters.index(transformed_address) except ValueError: # If the node is no longer a transmitter of this contract, # move on to the next contract @@ -541,7 +536,7 @@ def _get_v4_data(self, w3_interface: Web3, node_eth_address: str, 'latestTimestamp': latest_round_data[3], 'answeredInRound': latest_round_data[4], 'owedPayment': aggregator_contract.functions.owedPayment( - transformed_eth_address).call(), + transformed_address).call(), 'historicalRounds': [] } @@ -588,19 +583,19 @@ def _get_v4_data(self, w3_interface: Web3, node_eth_address: str, return data - def _get_data(self, w3_interface: Web3, node_eth_address: str, + def _get_data(self, w3_interface: Web3, node_address: str, node_id: str) -> Dict: """ This function retrieves the contracts' v3 and v4 metrics data for a single node using an evm node as data source. :param w3_interface: The web3 interface associated with the evm node - : used as data source - :param node_eth_address: The Ethereum address of the node - :param node_id: The identifier of the node - :return: A dict containing all contract metrics + : used as data source. + :param node_address: The address of the node. + :param node_id: The identifier of the node. + :return: A dict containing all contract metrics. """ - v3_data = self._get_v3_data(w3_interface, node_eth_address, node_id) - v4_data = self._get_v4_data(w3_interface, node_eth_address, node_id) + v3_data = self._get_v3_data(w3_interface, node_address, node_id) + v4_data = self._get_v4_data(w3_interface, node_address, node_id) return {**v3_data, **v4_data} def _display_data(self, data: Dict) -> str: @@ -696,16 +691,16 @@ def _monitor(self) -> None: self.logger.error(data_retrieval_exception.message) self.logger.exception(e) - # Retrieve the eth address of the node every time period - if self.eth_address_retrieval_limiter.can_do_task(): - node_eth_address, error_occurred = self._get_nodes_eth_address() - self._store_nodes_eth_addresses(node_eth_address) + # Retrieve the address of the node every time period + if self.address_retrieval_limiter.can_do_task(): + node_address, error_occurred = self._get_nodes_address() + self._store_nodes_addresses(node_address) re_filter = True - # If an error occurred we want to get the eth address again in the + # If an error occurred we want to get the address again in the # next monitoring round if not error_occurred: - self.eth_address_retrieval_limiter.did_task() + self.address_retrieval_limiter.did_task() if not data_retrieval_failed: # Select an evm node for contract metrics retrieval if no data @@ -735,8 +730,8 @@ def _monitor(self) -> None: # If a url was selected, we need to retrieve the contract's # metrics if re_filter: - # If contracts or eth addresses were retrieved in this - # round, then we must do the re-filtering. + # If contracts or addresses were retrieved in this round, + # then we must do the re-filtering. try: node_contracts = self._filter_contracts_by_node( selected_node_url) @@ -746,9 +741,9 @@ def _monitor(self) -> None: "using %s", selected_node_url) self.logger.exception(e) w3_interface = self.evm_node_w3_interface[selected_node_url] - for node_id, node_eth_address in self.node_eth_address.items(): + for node_id, node_address in self.node_address.items(): try: - data = self._get_data(w3_interface, node_eth_address, + data = self._get_data(w3_interface, node_address, node_id) except (ReqConnectionError, ReadTimeout, IncompleteRead, ChunkedEncodingError, ProtocolError, InvalidURL, diff --git a/alerter/src/monitors/node/chainlink.py b/alerter/src/monitors/node/chainlink.py index 6eabc44b7..8b5b92ea5 100644 --- a/alerter/src/monitors/node/chainlink.py +++ b/alerter/src/monitors/node/chainlink.py @@ -2,7 +2,7 @@ import json import logging from collections import ChainMap, defaultdict -from datetime import datetime +from datetime import datetime, timedelta from http.client import IncompleteRead from typing import Dict, Callable @@ -15,12 +15,14 @@ from src.configs.nodes.chainlink import ChainlinkNodeConfig from src.message_broker.rabbitmq import RabbitMQApi from src.monitors.monitor import Monitor +from src.utils.constants.data import CHAINLINK_CHAINS_URL from src.utils.constants.rabbitmq import (RAW_DATA_EXCHANGE, CHAINLINK_NODE_RAW_DATA_ROUTING_KEY) -from src.utils.data import get_prometheus_metrics_data +from src.utils.data import get_prometheus_metrics_data, get_json from src.utils.exceptions import (NodeIsDownException, PANICException, DataReadingException, InvalidUrlException, MetricNotFoundException) +from src.utils.timing import TimedTaskLimiter class ChainlinkNodeMonitor(Monitor): @@ -44,6 +46,8 @@ def __init__(self, monitor_name: str, node_config: ChainlinkNodeConfig, 'run_status_update_total': 'optional', } self._last_prometheus_source_used = node_config.node_prometheus_urls[0] + self._currency_symbol_limiter = TimedTaskLimiter(timedelta(hours=24)) + self._currency_symbol = '' @property def node_config(self) -> ChainlinkNodeConfig: @@ -57,6 +61,14 @@ def prometheus_metrics(self) -> Dict[str, str]: def last_prometheus_source_used(self) -> str: return self._last_prometheus_source_used + @property + def currency_symbol_limiter(self) -> TimedTaskLimiter: + return self._currency_symbol_limiter + + @property + def currency_symbol(self) -> str: + return self._currency_symbol + def _display_data(self, data: Dict) -> str: # This function attempts to display all metric values. If a particular # source is disabled, then that metric will not appear in the data, so @@ -71,7 +83,7 @@ def _display_data(self, data: Dict) -> str: "process_start_time_seconds={}, tx_manager_num_gas_bumps_total={}, " "tx_manager_gas_bump_exceeds_limit_total={}, " "unconfirmed_transactions={}, gas_updater_set_gas_price={}, " - "eth_balance={}, run_status_update_total_errors={}" + "balance={}, run_status_update_total_errors={}" "".format( data_defaultdict['head_tracker_current_head'], data_defaultdict['head_tracker_heads_received_total'], @@ -81,7 +93,7 @@ def _display_data(self, data: Dict) -> str: data_defaultdict['tx_manager_gas_bump_exceeds_limit_total'], data_defaultdict['unconfirmed_transactions'], data_defaultdict['gas_updater_set_gas_price'], - data_defaultdict['eth_balance'], + data_defaultdict['balance'], data_defaultdict['run_status_update_total_errors']) ) @@ -256,20 +268,27 @@ def _process_retrieved_prometheus_data(self, data: Dict) -> Dict: processed_data['result']['data'][ 'gas_updater_set_gas_price']) - # Add the ethereum balance to the processed data. We will monitor the - # first account we find. - processed_data['result']['data']['eth_balance'] = {} - ethereum_balance_dict = processed_data['result']['data']['eth_balance'] + # Add the balance to the processed data. We will monitor the first + # account we find. + processed_data['result']['data']['balance'] = {} + balance_dict = processed_data['result']['data']['balance'] for _, data_subset in enumerate(data_copy['eth_balance']): data_subset_json = json.loads(data_subset) if "account" in data_subset_json: - eth_address = data_subset_json['account'] - ethereum_balance_dict['address'] = eth_address - ethereum_balance_dict['balance'] = data_copy['eth_balance'][ - data_subset] + address = data_subset_json['account'] + balance_dict['address'] = address + balance_dict['balance'] = data_copy['eth_balance'][data_subset] + if "evmChainID" in data_subset_json: + evm_chain_id = int(data_subset_json['evmChainID']) + if self.currency_symbol_limiter.can_do_task(): + self._currency_symbol = self._get_currency_symbol( + evm_chain_id) + if self.currency_symbol: + self.currency_symbol_limiter.did_task() + balance_dict['symbol'] = self.currency_symbol break - self.logger.debug("%s eth_balance: %s", self.node_config, - processed_data['result']['data']['eth_balance']) + self.logger.debug("%s balance: %s", self.node_config, + processed_data['result']['data']['balance']) # Add the number of error job runs to the processed data no_of_error_job_runs = 0 @@ -355,3 +374,27 @@ def _monitor(self) -> None: 'timestamp': datetime.now().timestamp() } self._send_heartbeat(heartbeat) + + def _get_currency_symbol(self, chain_id: int) -> str: + """ + This function gets a list of chains from an endpoint, finds the chain + with the ID passed as a parameter and returns the currency symbol of + said chain. + :param chain_id: The ID of the chain of which we need to return the + currency symbol for. + :return: The currency symbol for the given chain ID + """ + currency_symbol = '' + + try: + chains = get_json(CHAINLINK_CHAINS_URL, self.logger) + self.logger.debug("Retrieved chains data from endpoint: %s", + CHAINLINK_CHAINS_URL) + + found_chain = next(chain for chain in chains + if chain['chainId'] == chain_id) + currency_symbol = found_chain['nativeCurrency']['symbol'] + except Exception as e: + self.logger.exception(e) + + return currency_symbol diff --git a/alerter/src/utils/constants/data.py b/alerter/src/utils/constants/data.py index 39749c829..1ad784429 100644 --- a/alerter/src/utils/constants/data.py +++ b/alerter/src/utils/constants/data.py @@ -20,7 +20,7 @@ 'tx_manager_gas_bump_exceeds_limit_total': 'total_gas_bumps_exceeds_limit', 'unconfirmed_transactions': 'no_of_unconfirmed_txs', 'gas_updater_set_gas_price': 'current_gas_price_info', - 'eth_balance': 'eth_balance_info', + 'balance': 'balance_info', 'run_status_update_total_errors': 'total_errored_job_runs', } RAW_TO_TRANSFORMED_COSMOS_NODE_PROM_METRICS = { @@ -36,7 +36,7 @@ EXPIRE_METRICS = [ GroupedChainlinkNodeAlertsMetricCode.ChangeInSourceNode, GroupedChainlinkNodeAlertsMetricCode.GasBumpIncreasedOverNodeGasPriceLimit, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceTopUp, + GroupedChainlinkNodeAlertsMetricCode.BalanceTopUp, GroupedCosmosNodeAlertsMetricCode.ValidatorWasSlashed, GroupedCosmosNetworkAlertsMetricCode.NewProposalSubmitted, GroupedCosmosNetworkAlertsMetricCode.ProposalConcluded, @@ -56,3 +56,5 @@ GroupedCosmosNetworkAlertsMetricCode.NoSyncedCosmosRestSource, GroupedCosmosNetworkAlertsMetricCode.CosmosNetworkDataNotObtained, ] + +CHAINLINK_CHAINS_URL = 'https://chainid.network/chains_mini.json' diff --git a/alerter/src/utils/constants/names.py b/alerter/src/utils/constants/names.py index 09d2d0dc7..5171d9c9e 100644 --- a/alerter/src/utils/constants/names.py +++ b/alerter/src/utils/constants/names.py @@ -1,4 +1,5 @@ # Component names/name templates/ids +SYSTEM_ALERTER_NAME = 'System Alerter' GITHUB_ALERTER_NAME = 'GitHub Alerter' DOCKERHUB_ALERTER_NAME = 'DockerHub Alerter' CHAINLINK_NODE_ALERTER_NAME = 'Chainlink Node Alerter' @@ -50,7 +51,6 @@ TELEGRAM_COMMAND_HANDLERS_NAME = 'Telegram Command Handlers' SLACK_COMMAND_HANDLERS_NAME = 'Slack Command Handlers' LOG_CHANNEL_ID = 'LOG' -SYSTEM_ALERTER_NAME_TEMPLATE = 'System alerter ({})' GITHUB_MONITOR_NAME_TEMPLATE = 'GitHub monitor ({})' DOCKERHUB_MONITOR_NAME_TEMPLATE = 'DockerHub monitor ({})' SYSTEM_MONITOR_NAME_TEMPLATE = 'System monitor ({})' diff --git a/alerter/src/utils/constants/rabbitmq.py b/alerter/src/utils/constants/rabbitmq.py index d81e2b4f8..5e4909425 100644 --- a/alerter/src/utils/constants/rabbitmq.py +++ b/alerter/src/utils/constants/rabbitmq.py @@ -37,7 +37,7 @@ COSMOS_NETWORK_DT_INPUT_QUEUE_NAME = \ 'cosmos_network_data_transformer_input_queue' DT_MAN_HEARTBEAT_QUEUE_NAME = 'data_transformers_manager_heartbeat_queue' -SYS_ALERTER_INPUT_QUEUE_NAME_TEMPLATE = "system_alerter_input_queue_{}" +SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME = "system_alerter_input_configs_queue" GITHUB_ALERTER_INPUT_QUEUE_NAME = 'github_alerter_input_queue' EVM_NODE_ALERTER_INPUT_CONFIGS_QUEUE_NAME = \ 'evm_node_alerter_input_configs_queue' @@ -51,8 +51,7 @@ 'cosmos_network_alerter_input_configs_queue' SYS_ALERTERS_MAN_HEARTBEAT_QUEUE_NAME = \ 'system_alerters_manager_heartbeat_queue' -SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME = \ - 'system_alerters_manager_configs_queue' +SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME = 'system_alerters_manager_configs_queue' GH_ALERTERS_MAN_HEARTBEAT_QUEUE_NAME = 'github_alerters_manager_heartbeat_queue' DH_ALERTERS_MAN_HEARTBEAT_QUEUE_NAME = \ 'dockerhub_alerters_manager_heartbeat_queue' @@ -103,7 +102,7 @@ EVM_NODES_CONFIGS_ROUTING_KEY_CHAINS = 'chains.*.*.evm_nodes_config' GITHUB_TRANSFORMED_DATA_ROUTING_KEY = 'transformed_data.github' DOCKERHUB_TRANSFORMED_DATA_ROUTING_KEY = 'transformed_data.dockerhub' -SYSTEM_TRANSFORMED_DATA_ROUTING_KEY_TEMPLATE = 'transformed_data.system.{}' +SYSTEM_TRANSFORMED_DATA_ROUTING_KEY = 'transformed_data.system' CL_NODE_TRANSFORMED_DATA_ROUTING_KEY = 'transformed_data.node.chainlink' COSMOS_NODE_TRANSFORMED_DATA_ROUTING_KEY = 'transformed_data.node.cosmos' COSMOS_NETWORK_TRANSFORMED_DATA_ROUTING_KEY = 'transformed_data.network.cosmos' @@ -126,7 +125,6 @@ ALERT_ROUTER_INPUT_ROUTING_KEY = 'alert.#' ALERT_STORE_INPUT_ROUTING_KEY = 'alert' MONITORABLE_STORE_INPUT_ROUTING_KEY = '*.*' -SYSTEM_STORE_INPUT_ROUTING_KEY = 'transformed_data.system.*' CHANNEL_HANDLER_INPUT_ROUTING_KEY_TEMPLATE = 'channel.{}' CONSOLE_HANDLER_INPUT_ROUTING_KEY = "channel.console" LOG_HANDLER_INPUT_ROUTING_KEY = 'channel.log' diff --git a/alerter/src/utils/types.py b/alerter/src/utils/types.py index a21cbd5d4..5f1f1fb20 100644 --- a/alerter/src/utils/types.py +++ b/alerter/src/utils/types.py @@ -47,11 +47,11 @@ ClNodeTotalErroredJobRunsDecreasedBelowThresholdAlert, TotalErroredJobRunsIncreasedAboveThresholdAlert as ClNodeTotalErroredJobRunsIncreasedAboveThresholdAlert, - EthBalanceIncreasedAboveThresholdAlert as - ClNodeEthBalanceIncreasedAboveThresholdAlert, - EthBalanceDecreasedBelowThresholdAlert as - ClNodeEthBalanceDecreasedBelowThresholdAlert, - EthBalanceToppedUpAlert as ClNodeEthBalanceToppedUpAlert, + BalanceIncreasedAboveThresholdAlert as + ClNodeBalanceIncreasedAboveThresholdAlert, + BalanceDecreasedBelowThresholdAlert as + ClNodeBalanceDecreasedBelowThresholdAlert, + BalanceToppedUpAlert as ClNodeBalanceToppedUpAlert, InvalidUrlAlert as ClNodeInvalidUrlAlert, ValidUrlAlert as ClNodeValidUrlAlert, MetricNotFoundErrorAlert as ClNodeMetricNotFoundErrorAlert, @@ -134,7 +134,8 @@ OpenFileDescriptorsDecreasedBelowThresholdAlert, SystemCPUUsageDecreasedBelowThresholdAlert, SystemRAMUsageDecreasedBelowThresholdAlert, - SystemStorageUsageDecreasedBelowThresholdAlert + SystemStorageUsageDecreasedBelowThresholdAlert, SystemWentDownAtAlert, + SystemStillDownAlert, SystemBackUpAgainAlert ) from src.configs.alerts.contract.chainlink import ChainlinkContractAlertsConfig from src.configs.alerts.network.cosmos import CosmosNetworkAlertsConfig @@ -157,8 +158,6 @@ CosmosNode, CosmosNetwork, V4ChainlinkContract, V3ChainlinkContract] -# TODO: The below system alerts must be refactored to the types beneath them -# : when the system alerter is refactored. IncreasedAboveThresholdSystemAlert = Union[ OpenFileDescriptorsIncreasedAboveThresholdAlert, SystemCPUUsageIncreasedAboveThresholdAlert, @@ -197,7 +196,7 @@ ClNodeMaxUnconfirmedBlocksIncreasedAboveThresholdAlert, ClNodeNoOfUnconfirmedTxsIncreasedAboveThresholdAlert, ClNodeTotalErroredJobRunsIncreasedAboveThresholdAlert, - ClNodeEthBalanceIncreasedAboveThresholdAlert, + ClNodeBalanceIncreasedAboveThresholdAlert, ClContractPriceFeedObservationsMissedIncreasedAboveThreshold, ClContractPriceFeedDeviationIncreasedAboveThreshold, EVMNodeBlockHeightDifferenceIncreasedAboveThresholdAlert @@ -206,7 +205,7 @@ ClNodeMaxUnconfirmedBlocksDecreasedBelowThresholdAlert, ClNodeNoOfUnconfirmedTxsDecreasedBelowThresholdAlert, ClNodeTotalErroredJobRunsDecreasedBelowThresholdAlert, - ClNodeEthBalanceDecreasedBelowThresholdAlert, + ClNodeBalanceDecreasedBelowThresholdAlert, ClContractPriceFeedDeviationDecreasedBelowThreshold, EVMNodeBlockHeightDifferenceDecreasedBelowThresholdAlert ] @@ -219,10 +218,12 @@ CosmosNodeBlocksMissedDecreasedBelowThresholdAlert ] IncreasedAboveThresholdAlert = Union[ + IncreasedAboveThresholdSystemAlert, IncreasedAboveThresholdChainlinkNodeAlert, IncreasedAboveThresholdCosmosNodeAlert ] DecreasedBelowThresholdAlert = Union[ + DecreasedBelowThresholdSystemAlert, DecreasedBelowThresholdChainlinkNodeAlert, DecreasedBelowThresholdCosmosNodeAlert ] @@ -230,7 +231,7 @@ ChainlinkNodeConditionalAlert = Union[ ClNodeChangeInSourceNodeAlert, ClNodeGasBumpIncreasedOverNodeGasPriceLimitAlert, - ClNodeEthBalanceToppedUpAlert, ClNodePrometheusSourceIsDownAlert, + ClNodeBalanceToppedUpAlert, ClNodePrometheusSourceIsDownAlert, ClNodePrometheusSourceBackUpAgainAlert, ClContractPriceFeedObservedAgain, ClContractConsensusFailure ] @@ -291,20 +292,20 @@ ] DownAlert = Union[ - ClNodeNodeWentDownAtAlert, CosmosNodeNodeWentDownAtAlert, - CosmosNodePrometheusSourceIsDownAlert, + SystemWentDownAtAlert, ClNodeNodeWentDownAtAlert, + CosmosNodeNodeWentDownAtAlert, CosmosNodePrometheusSourceIsDownAlert, CosmosNodeCosmosRestSourceIsDownAlert, CosmosNodeTendermintRPCSourceIsDownAlert ] StillDownAlert = Union[ - ClNodeNodeStillDownAlert, CosmosNodeNodeStillDownAlert, - CosmosNodePrometheusSourceStillDownAlert, + SystemStillDownAlert, ClNodeNodeStillDownAlert, + CosmosNodeNodeStillDownAlert, CosmosNodePrometheusSourceStillDownAlert, CosmosNodeCosmosRestSourceStillDownAlert, CosmosNodeTendermintRPCSourceStillDownAlert ] BackUpAlert = Union[ - ClNodeNodeBackUpAgainAlert, CosmosNodeNodeBackUpAgainAlert, - CosmosNodePrometheusSourceBackUpAgainAlert, + SystemBackUpAgainAlert, ClNodeNodeBackUpAgainAlert, + CosmosNodeNodeBackUpAgainAlert, CosmosNodePrometheusSourceBackUpAgainAlert, CosmosNodeCosmosRestSourceBackUpAgainAlert, CosmosNodeTendermintRPCSourceBackUpAgainAlert ] diff --git a/alerter/test/alerter/alerters/node/test_chainlink.py b/alerter/test/alerter/alerters/node/test_chainlink.py index bcea6d0c5..1710aedb0 100644 --- a/alerter/test/alerter/alerters/node/test_chainlink.py +++ b/alerter/test/alerter/alerters/node/test_chainlink.py @@ -22,8 +22,8 @@ NoOfUnconfirmedTxsDecreasedBelowThresholdAlert, TotalErroredJobRunsIncreasedAboveThresholdAlert, TotalErroredJobRunsDecreasedBelowThresholdAlert, - EthBalanceIncreasedAboveThresholdAlert, - EthBalanceDecreasedBelowThresholdAlert, EthBalanceToppedUpAlert, + BalanceIncreasedAboveThresholdAlert, + BalanceDecreasedBelowThresholdAlert, BalanceToppedUpAlert, ChangeInSourceNodeAlert, GasBumpIncreasedOverNodeGasPriceLimitAlert, NodeWentDownAtAlert, NodeStillDownAlert, NodeBackUpAgainAlert, PrometheusSourceIsDownAlert, PrometheusSourceBackUpAgainAlert) @@ -77,8 +77,9 @@ def setUp(self) -> None: 'percentile': 50.5, 'price': 22.0, } - self.test_eth_balance_info = { + self.test_balance_info = { 'address': 'address1', 'balance': 34.4, 'latest_usage': 5.0, + 'symbol': 'TEST' } self.test_last_prometheus_source_used = "prometheus_source_1" self.test_last_monitored_prometheus = 45.666786 @@ -95,8 +96,9 @@ def setUp(self) -> None: 'percentile': 52.5, 'price': 24.0, } - self.test_eth_balance_info_new = { + self.test_balance_info_new = { 'address': 'address1', 'balance': 44.4, 'latest_usage': 0.0, + 'symbol': 'TEST' } self.test_last_prometheus_source_used_new = "prometheus_source_2" self.test_last_monitored_prometheus_new = 47.666786 @@ -110,7 +112,7 @@ def setUp(self) -> None: } metrics_without_time_window = [ 'head_tracker_current_head', 'head_tracker_heads_received_total', - 'eth_balance_amount', 'node_is_down' + 'balance_amount', 'node_is_down' ] metrics_with_time_window = [ 'max_unconfirmed_blocks', @@ -119,7 +121,7 @@ def setUp(self) -> None: severity_metrics = [ 'process_start_time_seconds', 'tx_manager_gas_bump_exceeds_limit_total', - 'eth_balance_amount_increase' + 'balance_amount_increase' ] all_metrics = (metrics_without_time_window + metrics_with_time_window @@ -212,9 +214,9 @@ def setUp(self) -> None: 'current': self.test_current_gas_price_info_new, 'previous': self.test_current_gas_price_info }, - 'eth_balance_info': { - 'current': self.test_eth_balance_info_new, - 'previous': self.test_eth_balance_info + 'balance_info': { + 'current': self.test_balance_info_new, + 'previous': self.test_balance_info }, }, } @@ -687,7 +689,7 @@ def test_process_prometheus_result_does_not_classify_if_metrics_disabled( @mock.patch.object(ChainlinkNodeAlertingFactory, "classify_conditional_alert") @mock.patch.object(ChainlinkNodeAlertingFactory, - "classify_thresholded_alert_reverse") + "classify_thresholded_alert_reverse_chainlink_node") def test_process_prometheus_result_classifies_correctly_if_data_valid( self, mock_reverse, mock_cond_alert, mock_thresh_per_alert, mock_thresh_win_alert, mock_no_change_alert, @@ -793,12 +795,13 @@ def test_process_prometheus_result_classifies_correctly_if_data_valid( calls = mock_reverse.call_args_list self.assertEqual(1, mock_reverse.call_count) call_1 = call( - self.test_eth_balance_info_new['balance'], - configs.eth_balance_amount, - EthBalanceIncreasedAboveThresholdAlert, - EthBalanceDecreasedBelowThresholdAlert, data_for_alerting, + self.test_balance_info_new['balance'], + configs.balance_amount, + self.test_balance_info_new['symbol'], + BalanceIncreasedAboveThresholdAlert, + BalanceDecreasedBelowThresholdAlert, data_for_alerting, self.test_parent_id, self.test_chainlink_node_id, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, self.test_chainlink_node_name, self.test_last_monitored_prometheus_new) self.assertTrue(call_1 in calls) @@ -806,15 +809,16 @@ def test_process_prometheus_result_classifies_correctly_if_data_valid( calls = mock_cond_alert.call_args_list self.assertEqual(3, mock_cond_alert.call_count) call_1 = call( - EthBalanceToppedUpAlert, + BalanceToppedUpAlert, self.test_cl_node_alerter._greater_than_condition_function, - [self.test_eth_balance_info_new['balance'], - self.test_eth_balance_info['balance']], [ + [self.test_balance_info_new['balance'], + self.test_balance_info['balance']], [ self.test_chainlink_node_name, - self.test_eth_balance_info_new['balance'], - self.test_eth_balance_info_new[ - 'balance'] - self.test_eth_balance_info['balance'], - configs.eth_balance_amount_increase['severity'], + self.test_balance_info_new['balance'], + self.test_balance_info_new[ + 'balance'] - self.test_balance_info['balance'], + self.test_balance_info_new['symbol'], + configs.balance_amount_increase['severity'], self.test_last_monitored_prometheus_new, self.test_parent_id, self.test_chainlink_node_id], data_for_alerting) call_2 = call( diff --git a/alerter/test/alerter/alerters/test_system.py b/alerter/test/alerter/alerters/test_system.py index 31eef7291..72ee7c335 100644 --- a/alerter/test/alerter/alerters/test_system.py +++ b/alerter/test/alerter/alerters/test_system.py @@ -3,8 +3,8 @@ import json import logging import unittest -from queue import Queue from unittest import mock +from unittest.mock import call import pika import pika.exceptions @@ -12,2801 +12,827 @@ from parameterized import parameterized from src.alerter.alerters.system import SystemAlerter -from src.alerter.alerts.system_alerts import ( - OpenFileDescriptorsIncreasedAboveThresholdAlert) -from src.alerter.grouped_alerts_metric_code import GroupedSystemAlertsMetricCode -from src.configs.alerts.system import SystemAlertsConfig +from src.alerter.alerts import system_alerts +from src.alerter.factory.system_alerting_factory import SystemAlertingFactory +from src.alerter.grouped_alerts_metric_code.system \ + import GroupedSystemAlertsMetricCode as MetricCode +from src.configs.factory.alerts.system_alerts import SystemAlertsConfigsFactory from src.message_broker.rabbitmq import RabbitMQApi from src.utils.constants.rabbitmq import ( - ALERT_EXCHANGE, HEALTH_CHECK_EXCHANGE, - SYS_ALERTER_INPUT_QUEUE_NAME_TEMPLATE, SYSTEM_ALERT_ROUTING_KEY, - SYSTEM_TRANSFORMED_DATA_ROUTING_KEY_TEMPLATE, - HEARTBEAT_OUTPUT_WORKER_ROUTING_KEY, TOPIC) -from src.utils.env import ALERTER_PUBLISHING_QUEUE_SIZE, RABBIT_IP + CONFIG_EXCHANGE, SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME, + HEALTH_CHECK_EXCHANGE, ALERT_EXCHANGE, + SYSTEM_TRANSFORMED_DATA_ROUTING_KEY, + SYSTEM_ALERT_ROUTING_KEY, ALERTS_CONFIGS_ROUTING_KEY_GEN) +from src.utils.env import RABBIT_IP +from src.utils.exceptions import ( + PANICException, SystemIsDownException, InvalidUrlException, + MetricNotFoundException) +from test.test_utils.utils import ( + connect_to_rabbit, delete_queue_if_exists, delete_exchange_if_exists, + disconnect_from_rabbit) class TestSystemAlerter(unittest.TestCase): def setUp(self) -> None: - self.dummy_logger = logging.getLogger('Dummy') + # Some dummy values and objects + self.test_alerter_name = 'test_alerter' + self.dummy_logger = logging.getLogger('dummy') self.dummy_logger.disabled = True - self.rabbit_ip = RABBIT_IP - self.alert_input_exchange = ALERT_EXCHANGE self.connection_check_time_interval = datetime.timedelta(seconds=0) - self.rabbitmq = RabbitMQApi( - self.dummy_logger, self.rabbit_ip, - connection_check_time_interval=self.connection_check_time_interval) - - self.test_rabbit_manager = RabbitMQApi( self.dummy_logger, RABBIT_IP, connection_check_time_interval=self.connection_check_time_interval) - - self.alerter_name = 'test_alerter' - self.system_id = 'test_system_id' - self.parent_id = 'test_parent_id' - self.system_name = 'test_system' - self.last_monitored = 1611619200 - self.publishing_queue = Queue(ALERTER_PUBLISHING_QUEUE_SIZE) - self.test_output_routing_key = 'test_alert.system' - self.queue_used = SYS_ALERTER_INPUT_QUEUE_NAME_TEMPLATE.format( - self.parent_id) - self.target_queue_used = "alert_router_queue" - self.input_routing_key = \ - SYSTEM_TRANSFORMED_DATA_ROUTING_KEY_TEMPLATE.format(self.parent_id) - self.bad_output_routing_key = "alert.system.not_real" - self.output_routing_key = SYSTEM_ALERT_ROUTING_KEY.format( - self.parent_id) - self.heartbeat_queue = 'heartbeat queue' - - self.heartbeat_test = { - 'component_name': self.alerter_name, - 'is_alive': True, - 'timestamp': datetime.datetime(2012, 1, 1).timestamp() + self.test_queue_size = 5 + self.test_parent_id = 'test_parent_id' + self.test_queue_name = 'Test Queue' + self.test_data_str = 'test_data_str' + self.test_configs_routing_key = 'chains.cosmos.cosmos.alerts_config' + self.test_configs_routing_key_gen = ALERTS_CONFIGS_ROUTING_KEY_GEN + self.test_system_name = 'test_system' + self.test_system_id = 'test_system_id345834t8h3r5893h8' + + # Some test metrics + self.test_went_down_at = None + self.test_last_monitored = datetime.datetime(2012, 1, 1).timestamp() + self.test_system_is_down_exception = SystemIsDownException( + self.test_system_name) + + # Construct received configurations + self.received_configurations = { + 'DEFAULT': 'testing_if_will_be_deleted' } + all_metrics = [ + 'open_file_descriptors', + 'system_cpu_usage', + 'system_storage_usage', + 'system_ram_usage', + 'system_is_down' + ] + + for i in range(len(all_metrics)): + self.received_configurations[str(i)] = { + 'name': all_metrics[i], + 'parent_id': self.test_parent_id, + 'enabled': 'true', + 'critical_threshold': '95', + 'critical_repeat': '300', + 'critical_enabled': 'true', + 'critical_repeat_enabled': 'true', + 'warning_threshold': '85', + 'warning_enabled': 'true', + } - """ - ############# Alerts config base configuration ###################### - """ - self.enabled_alert = "True" - self.critical_threshold_percentage = 95 - self.critical_threshold_seconds = 300 - self.critical_repeat_seconds = 300 - self.critical_enabled = "True" - self.critical_repeat_enabled = "True" - self.warning_threshold_percentage = 85 - self.warning_threshold_seconds = 200 - self.warning_enabled = "True" - - self.base_config = { - "name": "base_percent_config", - "enabled": self.enabled_alert, - "parent_id": self.parent_id, - "critical_threshold": self.critical_threshold_percentage, - "critical_repeat": self.critical_repeat_seconds, - "critical_repeat_enabled": self.critical_repeat_enabled, - "critical_enabled": self.critical_enabled, - "warning_threshold": self.warning_threshold_percentage, - "warning_enabled": self.warning_enabled - } - - self.open_file_descriptors = copy.deepcopy(self.base_config) - self.open_file_descriptors['name'] = "open_file_descriptors" - - self.system_cpu_usage = copy.deepcopy(self.base_config) - self.system_cpu_usage['name'] = "system_cpu_usage" - - self.system_storage_usage = copy.deepcopy(self.base_config) - self.system_storage_usage['name'] = "system_storage_usage" - - self.system_ram_usage = copy.deepcopy(self.base_config) - self.system_ram_usage['name'] = "system_ram_usage" - - self.system_is_down = copy.deepcopy(self.base_config) - self.system_is_down['name'] = "system_is_down" - self.system_is_down['critical_threshold'] = \ - self.critical_threshold_seconds - self.system_is_down['warning_threshold'] = \ - self.warning_threshold_seconds - - self.system_alerts_config = SystemAlertsConfig( - self.parent_id, - self.open_file_descriptors, - self.system_cpu_usage, - self.system_storage_usage, - self.system_ram_usage, - self.system_is_down - ) - self.test_system_alerter = SystemAlerter( - self.alerter_name, - self.system_alerts_config, - self.dummy_logger, - self.rabbitmq, - ALERTER_PUBLISHING_QUEUE_SIZE - ) - - """ - ############# Alerts config warning alerts disabled #################### - """ - - self.base_config['warning_enabled'] = str( - not bool(self.warning_enabled)) - self.open_file_descriptors = copy.deepcopy(self.base_config) - self.open_file_descriptors['name'] = "open_file_descriptors" - - self.system_cpu_usage = copy.deepcopy(self.base_config) - self.system_cpu_usage['name'] = "system_cpu_usage" - - self.system_storage_usage = copy.deepcopy(self.base_config) - self.system_storage_usage['name'] = "system_storage_usage" - - self.system_ram_usage = copy.deepcopy(self.base_config) - self.system_ram_usage['name'] = "system_ram_usage" - - self.system_is_down = copy.deepcopy(self.base_config) - self.system_is_down['name'] = "system_is_down" - self.system_is_down['critical_threshold'] = \ - self.critical_threshold_seconds - self.system_is_down['warning_threshold'] = \ - self.warning_threshold_seconds - - self.system_alerts_config_warnings_disabled = SystemAlertsConfig( - self.parent_id, - self.open_file_descriptors, - self.system_cpu_usage, - self.system_storage_usage, - self.system_ram_usage, - self.system_is_down - ) - self.test_system_alerter_warnings_disabled = SystemAlerter( - self.alerter_name, - self.system_alerts_config_warnings_disabled, - self.dummy_logger, - self.rabbitmq, - ALERTER_PUBLISHING_QUEUE_SIZE - ) - - """ - ############# Alerts config critical alerts disabled ################### - """ - self.base_config['warning_enabled'] = self.warning_enabled - self.base_config['critical_enabled'] = str( - not bool(self.critical_enabled)) - self.open_file_descriptors = copy.deepcopy(self.base_config) - self.open_file_descriptors['name'] = "open_file_descriptors" - - self.system_cpu_usage = copy.deepcopy(self.base_config) - self.system_cpu_usage['name'] = "system_cpu_usage" - - self.system_storage_usage = copy.deepcopy(self.base_config) - self.system_storage_usage['name'] = "system_storage_usage" - - self.system_ram_usage = copy.deepcopy(self.base_config) - self.system_ram_usage['name'] = "system_ram_usage" - - self.system_is_down = copy.deepcopy(self.base_config) - self.system_is_down['name'] = "system_is_down" - self.system_is_down['critical_threshold'] = \ - self.critical_threshold_seconds - self.system_is_down['warning_threshold'] = \ - self.warning_threshold_seconds - - self.system_alerts_config_critical_disabled = SystemAlertsConfig( - self.parent_id, - self.open_file_descriptors, - self.system_cpu_usage, - self.system_storage_usage, - self.system_ram_usage, - self.system_is_down - ) - - self.test_system_alerter_critical_disabled = SystemAlerter( - self.alerter_name, - self.system_alerts_config_critical_disabled, - self.dummy_logger, - self.rabbitmq, - ALERTER_PUBLISHING_QUEUE_SIZE - ) - - """ - ########## Alerts config critical repeat alerts disabled ############### - """ - self.base_config['warning_enabled'] = self.warning_enabled - self.base_config['critical_enabled'] = self.critical_enabled - self.base_config['critical_repeat_enabled'] = str( - not bool(self.critical_repeat_enabled)) - self.open_file_descriptors = copy.deepcopy(self.base_config) - self.open_file_descriptors['name'] = "open_file_descriptors" - - self.system_cpu_usage = copy.deepcopy(self.base_config) - self.system_cpu_usage['name'] = "system_cpu_usage" - - self.system_storage_usage = copy.deepcopy(self.base_config) - self.system_storage_usage['name'] = "system_storage_usage" - - self.system_ram_usage = copy.deepcopy(self.base_config) - self.system_ram_usage['name'] = "system_ram_usage" - - self.system_is_down = copy.deepcopy(self.base_config) - self.system_is_down['name'] = "system_is_down" - self.system_is_down['critical_threshold'] = \ - self.critical_threshold_seconds - self.system_is_down['warning_threshold'] = \ - self.warning_threshold_seconds - - self.system_alerts_config_critical_repeat_disabled = SystemAlertsConfig( - self.parent_id, - self.open_file_descriptors, - self.system_cpu_usage, - self.system_storage_usage, - self.system_ram_usage, - self.system_is_down - ) - - self.test_system_alerter_critical_repeat_disabled = SystemAlerter( - self.alerter_name, - self.system_alerts_config_critical_repeat_disabled, - self.dummy_logger, - self.rabbitmq, - ALERTER_PUBLISHING_QUEUE_SIZE - ) - - """ - ############# Alerts config all alerts disabled ###################### - """ - self.base_config['warning_enabled'] = self.warning_enabled - self.base_config['critical_enabled'] = self.critical_enabled - self.base_config['enabled'] = str(not bool(self.enabled_alert)) - self.open_file_descriptors = copy.deepcopy(self.base_config) - self.open_file_descriptors['name'] = "open_file_descriptors" - - self.system_cpu_usage = copy.deepcopy(self.base_config) - self.system_cpu_usage['name'] = "system_cpu_usage" - - self.system_storage_usage = copy.deepcopy(self.base_config) - self.system_storage_usage['name'] = "system_storage_usage" - - self.system_ram_usage = copy.deepcopy(self.base_config) - self.system_ram_usage['name'] = "system_ram_usage" - - self.system_is_down = copy.deepcopy(self.base_config) - self.system_is_down['name'] = "system_is_down" - self.system_is_down['critical_threshold'] = \ - self.critical_threshold_seconds - self.system_is_down['warning_threshold'] = \ - self.warning_threshold_seconds - - self.system_alerts_config_all_disabled = SystemAlertsConfig( - self.parent_id, - self.open_file_descriptors, - self.system_cpu_usage, - self.system_storage_usage, - self.system_ram_usage, - self.system_is_down - ) - - self.test_system_alerter_all_disabled = SystemAlerter( - self.alerter_name, - self.system_alerts_config_all_disabled, - self.dummy_logger, - self.rabbitmq, - ALERTER_PUBLISHING_QUEUE_SIZE - ) - - """ - ################# Metrics Received from Data Transformer ############ - """ - self.warning = "WARNING" - self.info = "INFO" - self.critical = "CRITICAL" - self.error = "ERROR" - self.none = None - # Process CPU Seconds Total - self.current_cpu_sec = 42420.88 - self.previous_cpu_sec = 42400.42 - # Process Memory Usage - self.current_mem_use = 20.00 - self.previous_mem_use = 10.23 - # Virtual Memory Usage - self.current_v_mem_use = 735047680.0 - self.previous_v_mem_use = 723312578.0 - self.percent_usage = 40 - - self.data_received_error_data = { - "error": { - "meta_data": { - "system_name": self.system_name, - "system_id": self.system_id, - "system_parent_id": self.parent_id, - "time": self.last_monitored + self.test_result_data = { + 'meta_data': { + 'system_name': self.test_system_name, + 'system_id': self.test_system_id, + 'system_parent_id': self.test_parent_id, + 'last_monitored': self.test_last_monitored + }, + 'data': { + 'open_file_descriptors': { + 'current': 96, + 'previous': 96 }, - "data": { - "went_down_at": { - "current": self.last_monitored, - "previous": self.none - } + 'system_cpu_usage': { + 'current': 96, + 'previous': 96 }, - "message": "Error message", - "code": 5004, - } + 'system_ram_usage': { + 'current': 96, + 'previous': 96, + }, + 'system_storage_usage': { + 'current': 96, + 'previous': 96, + }, + }, } - self.data_received_initially_no_alert = { - "result": { - "meta_data": { - "system_name": self.system_name, - "system_id": self.system_id, - "system_parent_id": self.parent_id, - "last_monitored": self.last_monitored - }, - "data": { - "process_cpu_seconds_total": { - "current": self.current_cpu_sec, - "previous": self.none - }, - "process_memory_usage": { - "current": self.current_mem_use, - "previous": self.none - }, - "virtual_memory_usage": { - "current": self.current_v_mem_use, - "previous": self.none - }, - "open_file_descriptors": { - "current": self.percent_usage, - "previous": self.none - }, - "system_cpu_usage": { - "current": self.percent_usage, - "previous": self.none - }, - "system_ram_usage": { - "current": self.percent_usage, - "previous": self.none - }, - "system_storage_usage": { - "current": self.percent_usage, - "previous": self.none - }, - "network_receive_bytes_total": { - "current": self.none, - "previous": self.none, - }, - "network_transmit_bytes_total": { - "current": self.none, - "previous": self.none - }, - "disk_io_time_seconds_total": { - "current": self.none, - "previous": self.none, - }, - "network_transmit_bytes_per_second": { - "current": self.none, - "previous": self.none, - }, - "network_receive_bytes_per_second": { - "current": self.none, - "previous": self.none - }, - "disk_io_time_seconds_in_interval": { - "current": self.none, - "previous": self.none, - }, - "went_down_at": { - "current": self.none, - "previous": self.none - } + self.test_system_down_error = { + 'meta_data': { + 'system_name': self.test_system_name, + 'system_id': self.test_system_id, + 'system_parent_id': self.test_parent_id, + 'time': self.test_last_monitored + }, + 'message': self.test_system_is_down_exception.message, + 'code': self.test_system_is_down_exception.code, + 'data': { + 'went_down_at': { + 'current': self.test_last_monitored + 60, + 'previous': None } } } - self.data_received_initially_warning_alert = \ - copy.deepcopy(self.data_received_initially_no_alert) - - self.data_received_initially_warning_alert[ - 'result']['data']['open_file_descriptors']['current'] = \ - self.percent_usage + 46 - self.data_received_initially_warning_alert[ - 'result']['data']['system_cpu_usage']['current'] = \ - self.percent_usage + 46 - self.data_received_initially_warning_alert[ - 'result']['data']['system_ram_usage']['current'] = \ - self.percent_usage + 46 - self.data_received_initially_warning_alert[ - 'result']['data']['system_storage_usage']['current'] = \ - self.percent_usage + 46 - - self.data_received_below_warning_threshold = \ - copy.deepcopy(self.data_received_initially_no_alert) - - self.data_received_below_warning_threshold[ - 'result']['data']['open_file_descriptors']['previous'] = \ - self.percent_usage + 46 - self.data_received_below_warning_threshold[ - 'result']['data']['system_cpu_usage']['previous'] = \ - self.percent_usage + 46 - self.data_received_below_warning_threshold[ - 'result']['data']['system_ram_usage']['previous'] = \ - self.percent_usage + 46 - self.data_received_below_warning_threshold[ - 'result']['data']['system_storage_usage']['previous'] = \ - self.percent_usage + 46 - - self.data_received_initially_critical_alert = \ - copy.deepcopy(self.data_received_initially_no_alert) - - self.data_received_initially_critical_alert[ - 'result']['data']['open_file_descriptors']['current'] = \ - self.percent_usage + 56 - self.data_received_initially_critical_alert[ - 'result']['data']['system_cpu_usage']['current'] = \ - self.percent_usage + 56 - self.data_received_initially_critical_alert[ - 'result']['data']['system_ram_usage']['current'] = \ - self.percent_usage + 56 - self.data_received_initially_critical_alert[ - 'result']['data']['system_storage_usage']['current'] = \ - self.percent_usage + 56 - - self.data_received_below_critical_above_warning = \ - copy.deepcopy(self.data_received_initially_warning_alert) - - self.data_received_below_critical_above_warning[ - 'result']['data']['open_file_descriptors']['previous'] = \ - self.percent_usage + 56 - self.data_received_below_critical_above_warning[ - 'result']['data']['system_cpu_usage']['previous'] = \ - self.percent_usage + 56 - self.data_received_below_critical_above_warning[ - 'result']['data']['system_ram_usage']['previous'] = \ - self.percent_usage + 56 - self.data_received_below_critical_above_warning[ - 'result']['data']['system_storage_usage']['previous'] = \ - self.percent_usage + 56 - - # Alert used for rabbitMQ testing - self.alert = OpenFileDescriptorsIncreasedAboveThresholdAlert( - self.system_name, self.percent_usage + 46, self.warning, - self.last_monitored, self.warning, self.parent_id, - self.system_id - ) - try: - self.test_system_alerter.rabbitmq.connect() - self.test_system_alerter.rabbitmq.exchange_declare( - HEALTH_CHECK_EXCHANGE, TOPIC, False, True, False, False) - self.test_system_alerter.rabbitmq.exchange_declare( - ALERT_EXCHANGE, TOPIC, False, True, False, False) - except Exception as e: - print("Setup failed: {}".format(e)) + self.transformed_data_example_result = { + 'result': copy.deepcopy(self.test_result_data) + } + + # Test object + self.test_configs_factory = SystemAlertsConfigsFactory() + self.test_alerting_factory = SystemAlertingFactory(self.dummy_logger) + self.test_system_alerter = SystemAlerter( + self.test_alerter_name, self.dummy_logger, + self.test_configs_factory, + self.rabbitmq, self.test_queue_size) def tearDown(self) -> None: # Delete any queues and exchanges which are common across many tests - try: - self.test_system_alerter.rabbitmq.connect() - self.test_rabbit_manager.connect() - # Declare the queues incase they aren't there, not to error - self.test_system_alerter.rabbitmq.queue_declare( - queue=self.target_queue_used, durable=True, exclusive=False, - auto_delete=False, passive=False - ) - self.test_system_alerter.rabbitmq.queue_declare( - queue=self.queue_used, durable=True, exclusive=False, - auto_delete=False, passive=False - ) - - self.test_system_alerter.rabbitmq.queue_purge(self.queue_used) - self.test_system_alerter.rabbitmq.queue_purge( - self.target_queue_used) - self.test_system_alerter.rabbitmq.queue_delete(self.queue_used) - self.test_system_alerter.rabbitmq.queue_delete( - self.target_queue_used) - self.test_system_alerter.rabbitmq.exchange_delete( - HEALTH_CHECK_EXCHANGE) - self.test_system_alerter.rabbitmq.exchange_delete(ALERT_EXCHANGE) - self.test_system_alerter.rabbitmq.disconnect() - self.test_rabbit_manager.disconnect() - except Exception as e: - print("Test failed: {}".format(e)) + connect_to_rabbit(self.test_system_alerter.rabbitmq) + delete_queue_if_exists(self.test_system_alerter.rabbitmq, + self.test_queue_name) + delete_queue_if_exists(self.test_system_alerter.rabbitmq, + SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME) + delete_exchange_if_exists(self.test_system_alerter.rabbitmq, + HEALTH_CHECK_EXCHANGE) + delete_exchange_if_exists(self.test_system_alerter.rabbitmq, + ALERT_EXCHANGE) + delete_exchange_if_exists(self.test_system_alerter.rabbitmq, + CONFIG_EXCHANGE) + disconnect_from_rabbit(self.test_system_alerter.rabbitmq) self.dummy_logger = None + self.connection_check_time_interval = None self.rabbitmq = None - self.publishing_queue = None - self.test_system_alerter = None - self.test_system_alerter_warnings_disabled = None - self.test_system_alerter_critical_disabled = None - self.test_system_alerter_all_disabled = None - self.test_system_alerter_critical_repeat_disabled = None - self.system_alerts_config = None - self.system_alerts_config_warnings_disabled = None - self.system_alerts_config_critical_disabled = None - self.system_alerts_config_all_disabled = None - self.system_alerts_config_critical_repeat_disabled = None + self.test_configs_factory = None + self.alerting_factory = None self.test_system_alerter = None + self.test_system_is_down_exception = None - def test_returns_alerter_name_as_str(self) -> None: - self.assertEqual(self.alerter_name, self.test_system_alerter.__str__()) - - def test_returns_alerter_name(self) -> None: - self.assertEqual(self.alerter_name, - self.test_system_alerter.alerter_name) - - def test_returns_logger(self) -> None: - self.assertEqual(self.dummy_logger, self.test_system_alerter.logger) - - def test_returns_publishing_queue_size(self) -> None: - self.assertEqual(self.publishing_queue.qsize(), - self.test_system_alerter.publishing_queue.qsize()) - - def test_returns_alerts_configs_from_alerter(self) -> None: - self.assertEqual(self.system_alerts_config, - self.test_system_alerter.alerts_configs) - - """ - ###################### Tests without using RabbitMQ ####################### - """ - - @mock.patch.object(SystemAlerter, "_classify_alert") - def test_alerts_initial_run_no_alerts_count_classify_alert( - self, mock_classify_alert) -> None: - data_for_alerting = [] - data = self.data_received_initially_no_alert['result']['data'] - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - self.assertEqual(4, mock_classify_alert.call_count) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageDecreasedBelowThresholdAlert", - autospec=True) - def test_initial_run_no_increase_alerts_or_decrease_alerts( - self, mock_storage_usage_decrease, mock_storage_usage_increase, - mock_ram_usage_decrease, mock_ram_usage_increase, - mock_cpu_usage_decrease, mock_cpu_usage_increase, - mock_ofd_decrease, mock_ofd_increase) -> None: - data_for_alerting = [] - data = self.data_received_initially_no_alert['result']['data'] - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - mock_storage_usage_decrease.assert_not_called() - mock_storage_usage_increase.assert_not_called() - mock_ram_usage_decrease.assert_not_called() - mock_ram_usage_increase.assert_not_called() - mock_cpu_usage_decrease.assert_not_called() - mock_cpu_usage_increase.assert_not_called() - mock_ofd_decrease.assert_not_called() - mock_ofd_increase.assert_not_called() - - self.assertEqual(0, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageDecreasedBelowThresholdAlert", - autospec=True) - def test_initial_run_no_alerts_second_run_no_alerts( - self, mock_storage_usage_decrease, mock_storage_usage_increase, - mock_ram_usage_decrease, mock_ram_usage_increase, - mock_cpu_usage_decrease, mock_cpu_usage_increase, - mock_ofd_decrease, mock_ofd_increase) -> None: - data_for_alerting = [] - data = self.data_received_initially_no_alert['result']['data'] - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - mock_storage_usage_decrease.assert_not_called() - mock_storage_usage_increase.assert_not_called() - mock_ram_usage_decrease.assert_not_called() - mock_ram_usage_increase.assert_not_called() - mock_cpu_usage_decrease.assert_not_called() - mock_cpu_usage_increase.assert_not_called() - mock_ofd_decrease.assert_not_called() - mock_ofd_increase.assert_not_called() - - self.assertEqual(0, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - mock_storage_usage_decrease.assert_not_called() - mock_storage_usage_increase.assert_not_called() - mock_ram_usage_decrease.assert_not_called() - mock_ram_usage_increase.assert_not_called() - mock_cpu_usage_decrease.assert_not_called() - mock_cpu_usage_increase.assert_not_called() - mock_ofd_decrease.assert_not_called() - mock_ofd_increase.assert_not_called() - - self.assertEqual(0, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @parameterized.expand([ - ('open_file_descriptors', 'mock_ofd_increase', '46', 'self.warning'), - ('open_file_descriptors', 'mock_ofd_increase', '56', 'self.critical'), - ('system_cpu_usage', 'mock_cpu_usage_increase', '46', 'self.warning'), - ('system_cpu_usage', 'mock_cpu_usage_increase', '56', 'self.critical'), - ('system_ram_usage', 'mock_ram_usage_increase', '46', 'self.warning'), - ('system_ram_usage', 'mock_ram_usage_increase', '56', 'self.critical'), - ('system_storage_usage', 'mock_storage_usage_increase', '46', - 'self.warning'), - ('system_storage_usage', 'mock_storage_usage_increase', '56', - 'self.critical'), - ]) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageDecreasedBelowThresholdAlert", - autospec=True) - def test_initial_run_no_increase_or_decrease_alerts_then_warning_or_critical_alert( - self, metric_param, mock_param, mock_pad, mock_severity, - mock_storage_usage_decrease, mock_storage_usage_increase, - mock_ram_usage_decrease, mock_ram_usage_increase, - mock_cpu_usage_decrease, mock_cpu_usage_increase, - mock_ofd_decrease, mock_ofd_increase) -> None: - data_for_alerting = [] - data = self.data_received_initially_no_alert['result']['data'] - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - mock_storage_usage_decrease.assert_not_called() - mock_storage_usage_increase.assert_not_called() - mock_ram_usage_decrease.assert_not_called() - mock_ram_usage_increase.assert_not_called() - mock_cpu_usage_decrease.assert_not_called() - mock_cpu_usage_increase.assert_not_called() - mock_ofd_decrease.assert_not_called() - mock_ofd_increase.assert_not_called() - - self.assertEqual(0, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - data[metric_param]['current'] = self.percent_usage + int(mock_pad) - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - mock_storage_usage_decrease.assert_not_called() - mock_ram_usage_decrease.assert_not_called() - mock_cpu_usage_decrease.assert_not_called() - mock_ofd_decrease.assert_not_called() - - eval(mock_param).assert_called_once_with( - self.system_name, data[metric_param]['current'], - eval(mock_severity), meta_data['last_monitored'], - eval(mock_severity), - self.parent_id, self.system_id - ) - - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch.object(SystemAlerter, "_classify_alert") - def test_alerts_initial_run_warning_alerts_count_classify_alert( - self, mock_classify_alert) -> None: - data_for_alerting = [] - data = self.data_received_initially_warning_alert['result']['data'] - meta_data = self.data_received_initially_warning_alert['result'][ - 'meta_data'] - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - self.assertEqual(4, mock_classify_alert.call_count) - self.assertEqual(0, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @parameterized.expand([ - ('open_file_descriptors', 'mock_ofd_increase', '46', 'self.warning'), - ('open_file_descriptors', 'mock_ofd_increase', '56', 'self.critical'), - ('system_cpu_usage', 'mock_cpu_usage_increase', '46', 'self.warning'), - ('system_cpu_usage', 'mock_cpu_usage_increase', '56', 'self.critical'), - ('system_ram_usage', 'mock_ram_usage_increase', '46', 'self.warning'), - ('system_ram_usage', 'mock_ram_usage_increase', '56', 'self.critical'), - ('system_storage_usage', 'mock_storage_usage_increase', '46', - 'self.warning'), - ('system_storage_usage', 'mock_storage_usage_increase', '56', - 'self.critical'), - ]) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageDecreasedBelowThresholdAlert", - autospec=True) - def test_initial_run_alerts_above_warning_and_critical_threshold( - self, metric_param, mock_param, mock_pad, mock_severity, - mock_storage_usage_decrease, mock_storage_usage_increase, - mock_ram_usage_decrease, mock_ram_usage_increase, - mock_cpu_usage_decrease, mock_cpu_usage_increase, - mock_ofd_decrease, mock_ofd_increase) -> None: - data_for_alerting = [] - data = self.data_received_initially_no_alert['result']['data'] - data[metric_param]['current'] = self.percent_usage + int(mock_pad) - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - mock_storage_usage_decrease.assert_not_called() - mock_ram_usage_decrease.assert_not_called() - mock_cpu_usage_decrease.assert_not_called() - mock_ofd_decrease.assert_not_called() - eval(mock_param).assert_called_once_with( - self.system_name, data[metric_param]['current'], - eval(mock_severity), meta_data['last_monitored'], - eval(mock_severity), self.parent_id, self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @parameterized.expand([ - ('open_file_descriptors', 'mock_ofd_increase', 'mock_ofd_decrease'), - ('system_cpu_usage', 'mock_cpu_usage_increase', - 'mock_cpu_usage_decrease'), - ('system_ram_usage', 'mock_ram_usage_increase', - 'mock_ram_usage_decrease'), - ('system_storage_usage', 'mock_storage_usage_increase', - 'mock_storage_usage_decrease'), - ]) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageDecreasedBelowThresholdAlert", - autospec=True) - def test_initial_run_warning_alert_then_info_alert_on_decrease( - self, metric_param, mock_param, mock_param_2, - mock_storage_usage_decrease, mock_storage_usage_increase, - mock_ram_usage_decrease, mock_ram_usage_increase, - mock_cpu_usage_decrease, mock_cpu_usage_increase, - mock_ofd_decrease, mock_ofd_increase) -> None: - data_for_alerting = [] - data = self.data_received_initially_no_alert['result']['data'] - data[metric_param]['current'] = self.percent_usage + 46 - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - mock_storage_usage_decrease.assert_not_called() - mock_ram_usage_decrease.assert_not_called() - mock_cpu_usage_decrease.assert_not_called() - mock_ofd_decrease.assert_not_called() - eval(mock_param).assert_called_once_with( - self.system_name, data[metric_param]['current'], - self.warning, meta_data['last_monitored'], self.warning, - self.parent_id, self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - data[metric_param]['current'] = self.percent_usage + 36 - data[metric_param]['previous'] = self.percent_usage + 46 - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - eval(mock_param_2).assert_called_once_with( - self.system_name, data[metric_param]['current'], - self.info, meta_data['last_monitored'], self.warning, - self.parent_id, self.system_id - ) - self.assertEqual(2, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @parameterized.expand([ - ('open_file_descriptors', 'mock_ofd_increase'), - ('system_cpu_usage', 'mock_cpu_usage_increase'), - ('system_ram_usage', 'mock_ram_usage_increase'), - ('system_storage_usage', 'mock_storage_usage_increase'), - ]) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageDecreasedBelowThresholdAlert", - autospec=True) - def test_initial_run_warning_alert_then_critical_alert( - self, metric_param, mock_param, mock_storage_usage_decrease, - mock_storage_usage_increase, mock_ram_usage_decrease, - mock_ram_usage_increase, mock_cpu_usage_decrease, - mock_cpu_usage_increase, mock_ofd_decrease, - mock_ofd_increase) -> None: - data_for_alerting = [] - data = self.data_received_initially_no_alert['result']['data'] - data[metric_param]['current'] = self.percent_usage + 46 - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - mock_storage_usage_decrease.assert_not_called() - mock_ram_usage_decrease.assert_not_called() - mock_cpu_usage_decrease.assert_not_called() - mock_ofd_decrease.assert_not_called() - eval(mock_param).assert_called_once_with( - self.system_name, data[metric_param]['current'], - self.warning, meta_data['last_monitored'], self.warning, - self.parent_id, self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - data[metric_param]['current'] = self.percent_usage + 56 - data[metric_param]['previous'] = self.percent_usage + 46 - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - mock_storage_usage_decrease.assert_not_called() - mock_ram_usage_decrease.assert_not_called() - mock_cpu_usage_decrease.assert_not_called() - mock_ofd_decrease.assert_not_called() - eval(mock_param).assert_called_with( - self.system_name, data[metric_param]['current'], - self.critical, meta_data['last_monitored'], self.critical, - self.parent_id, self.system_id - ) - self.assertEqual(2, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) + def test_alerts_configs_factory_returns_alerts_configs_factory( + self) -> None: + self.test_system_alerter._alerts_configs_factory = \ + self.test_configs_factory + self.assertEqual(self.test_configs_factory, + self.test_system_alerter.alerts_configs_factory) - @parameterized.expand([ - ('open_file_descriptors', 'mock_ofd_increase'), - ('system_cpu_usage', 'mock_cpu_usage_increase'), - ('system_ram_usage', 'mock_ram_usage_increase'), - ('system_storage_usage', 'mock_storage_usage_increase'), - ]) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageDecreasedBelowThresholdAlert", - autospec=True) - def test_initial_run_warning_alerts_then_increase_in_warning_no_alert( - self, metric_param, mock_param, mock_storage_usage_decrease, - mock_storage_usage_increase, mock_ram_usage_decrease, - mock_ram_usage_increase, mock_cpu_usage_decrease, - mock_cpu_usage_increase, mock_ofd_decrease, - mock_ofd_increase) -> None: - data_for_alerting = [] - data = self.data_received_initially_no_alert['result']['data'] - data[metric_param]['current'] = self.percent_usage + 46 - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - mock_storage_usage_decrease.assert_not_called() - mock_ram_usage_decrease.assert_not_called() - mock_cpu_usage_decrease.assert_not_called() - mock_ofd_decrease.assert_not_called() - eval(mock_param).assert_called_once_with( - self.system_name, data[metric_param]['current'], - self.warning, meta_data['last_monitored'], self.warning, - self.parent_id, self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - data[metric_param]['current'] = self.percent_usage + 47 - data[metric_param]['previous'] = self.percent_usage + 46 - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - mock_storage_usage_decrease.assert_not_called() - mock_ram_usage_decrease.assert_not_called() - mock_cpu_usage_decrease.assert_not_called() - mock_ofd_decrease.assert_not_called() - eval(mock_param).assert_called_once_with( - self.system_name, data[metric_param]['previous'], - self.warning, meta_data['last_monitored'], self.warning, - self.parent_id, self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) + def test_alerting_factory_returns_alerting_factory(self) -> None: + self.test_system_alerter._alerting_factory = self.test_alerting_factory + self.assertEqual(self.test_alerting_factory, + self.test_system_alerter.alerting_factory) - @parameterized.expand([ - ('open_file_descriptors', 'mock_ofd_increase', 'mock_ofd_decrease'), - ('system_cpu_usage', 'mock_cpu_usage_increase', - 'mock_cpu_usage_decrease'), - ('system_ram_usage', 'mock_ram_usage_increase', - 'mock_ram_usage_decrease'), - ('system_storage_usage', 'mock_storage_usage_increase', - 'mock_storage_usage_decrease'), - ]) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageDecreasedBelowThresholdAlert", - autospec=True) - def test_critical_alerts_then_no_increase_alerts_on_decrease_between_critical_and_warning( - self, metric_param, mock_param, mock_param_2, - mock_storage_usage_decrease, mock_storage_usage_increase, - mock_ram_usage_decrease, mock_ram_usage_increase, - mock_cpu_usage_decrease, mock_cpu_usage_increase, - mock_ofd_decrease, mock_ofd_increase) -> None: - data_for_alerting = [] - data = self.data_received_initially_no_alert['result']['data'] - data[metric_param]['current'] = self.percent_usage + 56 - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - mock_storage_usage_decrease.assert_not_called() - mock_ram_usage_decrease.assert_not_called() - mock_cpu_usage_decrease.assert_not_called() - mock_ofd_decrease.assert_not_called() - - eval(mock_param).assert_called_once_with( - self.system_name, data[metric_param]['current'], - self.critical, meta_data['last_monitored'], self.critical, - self.parent_id, self.system_id - ) - - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - data[metric_param]['current'] = self.percent_usage + 50 - data[metric_param]['previous'] = self.percent_usage + 56 - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - eval(mock_param_2).assert_called_once_with( - self.system_name, data[metric_param]['current'], - self.info, meta_data['last_monitored'], self.critical, - self.parent_id, self.system_id - ) - eval(mock_param).assert_called_once_with( - self.system_name, data[metric_param]['previous'], - self.critical, meta_data['last_monitored'], self.critical, - self.parent_id, self.system_id - ) - - self.assertEqual(2, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) + def test_initialise_rabbitmq_initialises_everything_as_expected( + self) -> None: + # To make sure that there is no connection/channel already + # established + self.assertIsNone(self.rabbitmq.connection) + self.assertIsNone(self.rabbitmq.channel) + + # To make sure that the exchanges and queues have not already been + # declared + connect_to_rabbit(self.rabbitmq) + self.rabbitmq.queue_delete(SYSTEM_ALERTER_INPUT_CONFIGS_QUEUE_NAME) + self.rabbitmq.exchange_delete(CONFIG_EXCHANGE) + self.rabbitmq.exchange_delete(HEALTH_CHECK_EXCHANGE) + self.rabbitmq.exchange_delete(ALERT_EXCHANGE) + disconnect_from_rabbit(self.rabbitmq) - @parameterized.expand([ - ('open_file_descriptors', 'mock_ofd_increase'), - ('system_cpu_usage', 'mock_cpu_usage_increase'), - ('system_ram_usage', 'mock_ram_usage_increase'), - ('system_storage_usage', 'mock_storage_usage_increase'), - ]) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system.TimedTaskLimiter.last_time_that_did_task", - autospec=True) - def test_critical_alerts_then_no_alerts_before_repeat_timer_elapsed( - self, metric_param, mock_param, mock_last_time_that_did_task, - mock_storage_usage_decrease, mock_storage_usage_increase, - mock_ram_usage_decrease, mock_ram_usage_increase, - mock_cpu_usage_decrease, mock_cpu_usage_increase, - mock_ofd_decrease, mock_ofd_increase) -> None: - mock_last_time_that_did_task.return_value = self.last_monitored - data_for_alerting = [] - data = self.data_received_initially_no_alert['result']['data'] - data[metric_param]['current'] = self.percent_usage + 56 - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - mock_storage_usage_decrease.assert_not_called() - mock_ram_usage_decrease.assert_not_called() - mock_cpu_usage_decrease.assert_not_called() - mock_ofd_decrease.assert_not_called() - eval(mock_param).assert_called_once_with( - self.system_name, data[metric_param]['current'], - self.critical, meta_data['last_monitored'], self.critical, - self.parent_id, self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - data[metric_param]['current'] = self.percent_usage + 58 - data[metric_param]['previous'] = self.percent_usage + 56 - meta_data['last_monitored'] = self.last_monitored + \ - self.critical_repeat_seconds - 1 - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - mock_storage_usage_decrease.assert_not_called() - mock_ram_usage_decrease.assert_not_called() - mock_cpu_usage_decrease.assert_not_called() - mock_ofd_decrease.assert_not_called() - eval(mock_param).assert_called_once_with( - self.system_name, data[metric_param]['previous'], - self.critical, self.last_monitored, self.critical, - self.parent_id, self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) + self.test_system_alerter._initialise_rabbitmq() - @parameterized.expand([ - ('open_file_descriptors', 'mock_ofd_increase'), - ('system_cpu_usage', 'mock_cpu_usage_increase'), - ('system_ram_usage', 'mock_ram_usage_increase'), - ('system_storage_usage', 'mock_storage_usage_increase'), - ]) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system.TimedTaskLimiter.last_time_that_did_task", - autospec=True) - def test_critical_alerts_then_critical_alert_on_same_value_after_repeat_timer_elapsed( - self, metric_param, mock_param, mock_last_time_that_did_task, - mock_storage_usage_decrease, mock_storage_usage_increase, - mock_ram_usage_decrease, mock_ram_usage_increase, - mock_cpu_usage_decrease, mock_cpu_usage_increase, - mock_ofd_decrease, mock_ofd_increase) -> None: - mock_last_time_that_did_task.return_value = self.last_monitored - data_for_alerting = [] - data = self.data_received_initially_no_alert['result']['data'] - data[metric_param]['current'] = self.percent_usage + 56 - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - mock_storage_usage_decrease.assert_not_called() - mock_ram_usage_decrease.assert_not_called() - mock_cpu_usage_decrease.assert_not_called() - mock_ofd_decrease.assert_not_called() - eval(mock_param).assert_called_once_with( - self.system_name, data[metric_param]['current'], - self.critical, meta_data['last_monitored'], self.critical, - self.parent_id, self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - meta_data['last_monitored'] = self.last_monitored + \ - self.critical_repeat_seconds - data[metric_param]['current'] = self.percent_usage + 56 - data[metric_param]['previous'] = self.percent_usage + 56 - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - mock_storage_usage_decrease.assert_not_called() - mock_ram_usage_decrease.assert_not_called() - mock_cpu_usage_decrease.assert_not_called() - mock_ofd_decrease.assert_not_called() - eval(mock_param).assert_called_with( - self.system_name, data[metric_param]['current'], - self.critical, meta_data['last_monitored'], self.critical, - self.parent_id, self.system_id - ) - self.assertEqual(2, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) + # Perform checks that the connection has been opened, marked as open + # and that the delivery confirmation variable is set. + self.assertTrue(self.test_system_alerter.rabbitmq.is_connected) + self.assertTrue(self.test_system_alerter.rabbitmq.connection.is_open) + self.assertTrue( + self.test_system_alerter.rabbitmq.channel._delivery_confirmation) + + # Check whether the producing exchanges have been created by using + # passive=True. If this check fails an exception is raised + # automatically. + self.test_system_alerter.rabbitmq.exchange_declare( + HEALTH_CHECK_EXCHANGE, passive=True) + + # Check whether the consuming exchanges and queues have been created + # by sending messages to them. Since at this point these queues have + # only the bindings from _initialise_rabbit, it must be that if no + # exception is raised, then all queues and exchanges have been created + # and binded correctly. + self.test_system_alerter.rabbitmq.basic_publish_confirm( + exchange=ALERT_EXCHANGE, + routing_key=SYSTEM_TRANSFORMED_DATA_ROUTING_KEY, + body=self.test_data_str, is_body_dict=False, + properties=pika.BasicProperties(delivery_mode=2), mandatory=True) + self.test_system_alerter.rabbitmq.basic_publish_confirm( + exchange=CONFIG_EXCHANGE, routing_key=self.test_configs_routing_key, + body=self.test_data_str, is_body_dict=False, + properties=pika.BasicProperties(delivery_mode=2), mandatory=True) + self.test_system_alerter.rabbitmq.basic_publish_confirm( + exchange=CONFIG_EXCHANGE, + routing_key=self.test_configs_routing_key_gen, + body=self.test_data_str, is_body_dict=False, + properties=pika.BasicProperties(delivery_mode=2), mandatory=True) @parameterized.expand([ - ('open_file_descriptors', 'mock_ofd_increase'), - ('system_cpu_usage', 'mock_cpu_usage_increase'), - ('system_ram_usage', 'mock_ram_usage_increase'), - ('system_storage_usage', 'mock_storage_usage_increase'), + (SYSTEM_TRANSFORMED_DATA_ROUTING_KEY, 'mock_proc_trans',), + ('chains.cosmos.cosmos.alerts_config', 'mock_proc_confs',), + ('unrecognized_routing_key', 'mock_basic_ack',), ]) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system.TimedTaskLimiter.last_time_that_did_task", - autospec=True) - def test_critical_alerts_then_critical_alert_on_lower_value_after_repeat_timer_elapsed( - self, metric_param, mock_param, mock_last_time_that_did_task, - mock_storage_usage_decrease, mock_storage_usage_increase, - mock_ram_usage_decrease, mock_ram_usage_increase, - mock_cpu_usage_decrease, mock_cpu_usage_increase, - mock_ofd_decrease, mock_ofd_increase) -> None: - mock_last_time_that_did_task.return_value = self.last_monitored - data_for_alerting = [] - data = self.data_received_initially_no_alert['result']['data'] - data[metric_param]['current'] = self.percent_usage + 57 - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - eval(mock_param).assert_called_once_with( - self.system_name, data[metric_param]['current'], - self.critical, meta_data['last_monitored'], self.critical, - self.parent_id, self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - meta_data['last_monitored'] = self.last_monitored + \ - self.critical_repeat_seconds - data[metric_param]['current'] = self.percent_usage + 56 - data[metric_param]['previous'] = self.percent_usage + 57 - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results(data, meta_data, - data_for_alerting) - try: - eval(mock_param).assert_called_with( - self.system_name, data[metric_param]['current'], - self.critical, meta_data['last_monitored'], self.critical, - self.parent_id, self.system_id - ) - self.assertEqual(2, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.SystemBackUpAgainAlert", - autospec=True) - def test_system_back_up_no_alert(self, mock_system_back_up) -> None: - data_for_alerting = [] - data = self.data_received_initially_no_alert['result']['data'] - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - mock_system_back_up.assert_not_called() - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.SystemBackUpAgainAlert", - autospec=True) - def test_system_back_up_alert(self, mock_system_back_up) -> None: - data_for_alerting = [] - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._system_initial_alert_sent[ - self.system_id][ - GroupedSystemAlertsMetricCode.SystemIsDown.value] = True - data = self.data_received_initially_no_alert['result']['data'] - data['went_down_at']['previous'] = self.last_monitored - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - mock_system_back_up.assert_called_once_with( - self.system_name, self.info, self.last_monitored, - self.parent_id, self.system_id - ) - # There are extra alerts due to initial start-up alerts - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.TimedTaskLimiter.reset", - autospec=True) - def test_system_back_up_timed_task_limiter_reset(self, mock_reset) -> None: - data_for_alerting = [] - self.test_system_alerter._create_state_for_system(self.system_id) - # Set that the initial downtime alert was sent already - self.test_system_alerter._system_initial_alert_sent[ - self.system_id][ - GroupedSystemAlertsMetricCode.SystemIsDown.value] = True - data = self.data_received_initially_no_alert['result']['data'] - data['went_down_at']['previous'] = self.last_monitored - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter._process_results( - data, meta_data, data_for_alerting) - try: - mock_reset.assert_called_once() - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.SystemWentDownAtAlert", - autospec=True) - def test_system_went_down_at_no_alert_below_warning_threshold( - self, mock_system_is_down) -> None: - data_for_alerting = [] - data = self.data_received_error_data['error'] - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_errors(data, data_for_alerting) - try: - mock_system_is_down.assert_not_called() - self.assertEqual(0, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) + @mock.patch.object(SystemAlerter, "_process_transformed_data") + @mock.patch.object(SystemAlerter, "_process_configs") + @mock.patch.object(RabbitMQApi, "basic_ack") + def test_process_data_calls_the_correct_sub_function( + self, routing_key, called_mock, mock_basic_ack, mock_proc_confs, + mock_proc_trans) -> None: + """ + In this test we will check that if a configs routing key is received, + the process_data function calls the process_configs fn, if a + transformed data routing key is received, the process_data function + calls the process_transformed_data fn, and if the routing key is + unrecognized, the process_data function calls the ack method. + """ + mock_basic_ack.return_value = None + mock_proc_confs.return_value = None + mock_proc_trans.return_value = None - """ - These tests assume that critical_threshold_seconds > - warning_threshold_seconds - """ + self.test_system_alerter.rabbitmq.connect() + blocking_channel = self.test_system_alerter.rabbitmq.channel + method = pika.spec.Basic.Deliver(routing_key=routing_key) + body = json.dumps(self.test_data_str) + properties = pika.spec.BasicProperties() + self.test_system_alerter._process_data(blocking_channel, method, + properties, body) - @mock.patch("src.alerter.alerters.system.SystemWentDownAtAlert", - autospec=True) - def test_system_went_down_at_alert_above_warning_threshold( - self, mock_system_is_down) -> None: - data_for_alerting = [] - data = self.data_received_error_data['error'] - data['meta_data']['time'] = self.last_monitored + \ - self.warning_threshold_seconds - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_errors(data, data_for_alerting) - try: - mock_system_is_down.assert_called_once_with( - self.system_name, self.warning, data['meta_data']['time'], - self.parent_id, self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.SystemWentDownAtAlert", - autospec=True) - def test_system_went_down_at_alert_above_critical_threshold( - self, mock_system_is_down) -> None: - data_for_alerting = [] - data = self.data_received_error_data['error'] - data['meta_data']['time'] = self.last_monitored + \ - self.critical_threshold_seconds - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_errors(data, data_for_alerting) - try: - mock_system_is_down.assert_called_once_with( - self.system_name, self.critical, data['meta_data']['time'], - self.parent_id, self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.SystemStillDownAlert", - autospec=True) - @mock.patch("src.alerter.alerters.system.SystemWentDownAtAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system.TimedTaskLimiter.last_time_that_did_task", - autospec=True) - def test_system_went_down_at_alert_above_warning_threshold_then_no_critical_repeat( - self, mock_last_time_did_task, mock_system_is_down, - mock_system_still_down) -> None: - data_for_alerting = [] - data = self.data_received_error_data['error'] - past_warning_time = self.last_monitored + self.warning_threshold_seconds - mock_last_time_did_task.return_value = past_warning_time - data['meta_data']['time'] = past_warning_time - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_errors( - data, data_for_alerting) - try: - mock_system_is_down.assert_called_once_with( - self.system_name, self.warning, past_warning_time, - self.parent_id, self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - data['meta_data'][ - 'time'] = past_warning_time + self.critical_repeat_seconds - 1 - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_errors( - data, data_for_alerting) - try: - mock_system_is_down.assert_called_once_with( - self.system_name, self.warning, past_warning_time, - self.parent_id, self.system_id - ) - mock_system_still_down.assert_not_called() - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.SystemStillDownAlert", - autospec=True) - @mock.patch("src.alerter.alerters.system.SystemWentDownAtAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system.TimedTaskLimiter.last_time_that_did_task", - autospec=True) - def test_system_went_down_at_alert_above_warning_threshold_then_critical_repeat( - self, mock_last_time_did_task, mock_system_is_down, - mock_system_still_down) -> None: - data_for_alerting = [] - data = self.data_received_error_data['error'] - past_warning_time = self.last_monitored + self.warning_threshold_seconds - mock_last_time_did_task.return_value = past_warning_time - data['meta_data']['time'] = past_warning_time - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_errors(data, data_for_alerting) - try: - mock_system_is_down.assert_called_once_with( - self.system_name, self.warning, past_warning_time, - self.parent_id, self.system_id - ) - self.assertEqual(2, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - data['meta_data'][ - 'time'] = past_warning_time + self.critical_repeat_seconds - downtime = int(data['meta_data']['time'] - self.last_monitored) - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_errors(data, data_for_alerting) - try: - mock_system_is_down.assert_called_once_with( - self.system_name, self.warning, past_warning_time, - self.parent_id, self.system_id - ) - mock_system_still_down.assert_called_once_with( - self.system_name, downtime, self.critical, - data['meta_data']['time'], self.parent_id, - self.system_id - ) - self.assertEqual(3, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.SystemStillDownAlert", - autospec=True) - @mock.patch("src.alerter.alerters.system.SystemWentDownAtAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system.TimedTaskLimiter.last_time_that_did_task", - autospec=True) - def test_system_went_down_at_alert_above_critical_threshold_then_no_critical_repeat( - self, mock_last_time_did_task, mock_system_is_down, - mock_system_still_down) -> None: - data_for_alerting = [] - data = self.data_received_error_data['error'] - past_critical_time = self.last_monitored + \ - self.critical_threshold_seconds - mock_last_time_did_task.return_value = past_critical_time - data['meta_data']['time'] = past_critical_time - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_errors(data, data_for_alerting) - try: - mock_system_is_down.assert_called_once_with( - self.system_name, self.critical, past_critical_time, - self.parent_id, self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - data['meta_data'][ - 'time'] = past_critical_time + self.critical_repeat_seconds - 1 - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_errors(data, data_for_alerting) - try: - mock_system_is_down.assert_called_once_with( - self.system_name, self.critical, past_critical_time, - self.parent_id, self.system_id - ) - mock_system_still_down.assert_not_called() - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.SystemStillDownAlert", - autospec=True) - @mock.patch("src.alerter.alerters.system.SystemWentDownAtAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system.TimedTaskLimiter.last_time_that_did_task", - autospec=True) - def test_system_went_down_at_alert_above_warning_threshold_then_critical_repeat( - self, mock_last_time_did_task, mock_system_is_down, - mock_system_still_down) -> None: - data_for_alerting = [] - data = self.data_received_error_data['error'] - past_critical_time = self.last_monitored + \ - self.critical_threshold_seconds - mock_last_time_did_task.return_value = past_critical_time - data['meta_data']['time'] = past_critical_time - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_errors(data, data_for_alerting) - try: - mock_system_is_down.assert_called_once_with( - self.system_name, self.critical, past_critical_time, - self.parent_id, self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - data['meta_data'][ - 'time'] = past_critical_time + self.critical_repeat_seconds - downtime = int(data['meta_data']['time'] - self.last_monitored) - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_errors( - data, data_for_alerting) - try: - mock_system_is_down.assert_called_once_with( - self.system_name, self.critical, past_critical_time, - self.parent_id, self.system_id - ) - mock_system_still_down.assert_called_once_with( - self.system_name, downtime, self.critical, - data['meta_data']['time'], self.parent_id, - self.system_id - ) - self.assertEqual(2, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) + eval(called_mock).assert_called_once() """ - Testing error alerts of MetricNotFound and InvalidURL + In the majority of the tests below we will perform mocking. The tests for + config processing and alerting were performed in separate test files which + targeted the factory classes. """ - @mock.patch("src.alerter.alerters.system.MetricNotFoundErrorAlert", - autospec=True) - def test_process_errors_metric_not_found_alert(self, mock_alert) -> None: - data_for_alerting = [] - data = self.data_received_error_data['error'] - data['code'] = 5003 - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_errors(data, data_for_alerting) - try: - mock_alert.assert_called_once_with( - self.system_name, data['message'], self.error, - data['meta_data']['time'], self.parent_id, - self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.MetricFoundAlert", - autospec=True) - @mock.patch("src.alerter.alerters.system.MetricNotFoundErrorAlert", - autospec=True) - def test_process_error_metric_not_found_alert_metric_found_alert(self, - mock_alert_not_found, - mock_alert_found) -> None: - - data_for_alerting = [] - data = self.data_received_error_data['error'] - data['code'] = 5003 - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_errors(data, data_for_alerting) - try: - mock_alert_not_found.assert_called_once_with( - self.system_name, data['message'], self.error, - data['meta_data']['time'], self.parent_id, - self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - data = self.data_received_error_data['error'] - data['code'] = 600000000 # This code doesn't exist - self.test_system_alerter._process_errors(data, data_for_alerting) - try: - mock_alert_found.assert_called_once_with( - self.system_name, "Metrics have been found!", self.info, - data['meta_data']['time'], self.parent_id, - self.system_id - ) - self.assertEqual(2, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.MetricFoundAlert", - autospec=True) - @mock.patch("src.alerter.alerters.system.MetricNotFoundErrorAlert", - autospec=True) - def test_process_error_metric_not_found_alert_process_result_metric_found_alert( - self, - mock_alert_not_found, mock_alert_found) -> None: - - data_for_alerting = [] - data = self.data_received_error_data['error'] - data['code'] = 5003 - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_errors(data, data_for_alerting) - try: - mock_alert_not_found.assert_called_once_with( - self.system_name, data['message'], self.error, - data['meta_data']['time'], self.parent_id, - self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - data = self.data_received_initially_no_alert['result']['data'] - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter._process_results(data, meta_data, - data_for_alerting) - try: - mock_alert_found.assert_called_once_with( - self.system_name, "Metrics have been found!", self.info, - meta_data['last_monitored'], self.parent_id, - self.system_id - ) - self.assertEqual(2, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.InvalidUrlAlert", autospec=True) - def test_process_errors_invalid_url_alert(self, mock_alert) -> None: - data_for_alerting = [] - data = self.data_received_error_data['error'] - data['code'] = 5009 - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_errors(data, data_for_alerting) - try: - mock_alert.assert_called_once_with( - self.system_name, data['message'], self.error, - data['meta_data']['time'], self.parent_id, - self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.ValidUrlAlert", autospec=True) - @mock.patch("src.alerter.alerters.system.InvalidUrlAlert", autospec=True) - def test_process_errors_invalid_url_alert_then_valid_url_alert(self, - mock_alert_invalid, - mock_alert_valid) -> None: - data_for_alerting = [] - data = self.data_received_error_data['error'] - data['code'] = 5009 - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_errors(data, data_for_alerting) - try: - mock_alert_invalid.assert_called_once_with( - self.system_name, data['message'], self.error, - data['meta_data']['time'], self.parent_id, - self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - data = self.data_received_error_data['error'] - data['code'] = 600000000 # This code doesn't exist - self.test_system_alerter._process_errors(data, data_for_alerting) - try: - mock_alert_valid.assert_called_once_with( - self.system_name, "Url is valid!", self.info, - data['meta_data']['time'], self.parent_id, - self.system_id - ) - self.assertEqual(2, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.ValidUrlAlert", autospec=True) - @mock.patch("src.alerter.alerters.system.InvalidUrlAlert", autospec=True) - def test_process_errors_invalid_url_alert_then_process_results_valid_url_alert( - self, - mock_alert_invalid, mock_alert_valid) -> None: - data_for_alerting = [] - data = self.data_received_error_data['error'] - data['code'] = 5009 - self.test_system_alerter._create_state_for_system(self.system_id) - self.test_system_alerter._process_errors(data, data_for_alerting) - try: - mock_alert_invalid.assert_called_once_with( - self.system_name, data['message'], self.error, - data['meta_data']['time'], self.parent_id, - self.system_id - ) - self.assertEqual(1, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - data = self.data_received_initially_no_alert['result']['data'] - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter._process_results(data, meta_data, - data_for_alerting) - try: - mock_alert_valid.assert_called_once_with( - self.system_name, "Url is valid!", self.info, - meta_data['last_monitored'], self.parent_id, - self.system_id - ) - self.assertEqual(2, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch.object(SystemAlerter, "_classify_alert") - def test_alerts_warning_alerts_disabled_metric_above_warning_threshold( - self, mock_classify_alert) -> None: - data_for_alerting = [] - data = self.data_received_initially_warning_alert['result']['data'] - meta_data = self.data_received_initially_warning_alert['result'][ - 'meta_data'] - self.test_system_alerter_warnings_disabled._create_state_for_system( - self.system_id) - self.test_system_alerter_warnings_disabled._process_results( - data, meta_data, data_for_alerting) - try: - self.assertEqual(4, mock_classify_alert.call_count) - self.assertEqual(0, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) + @mock.patch.object(SystemAlertsConfigsFactory, "get_parent_id") + @mock.patch.object(SystemAlertsConfigsFactory, "add_new_config") + @mock.patch.object(SystemAlertingFactory, "remove_chain_alerting_state") + @mock.patch.object(RabbitMQApi, "basic_ack") + def test_process_confs_adds_new_conf_and_clears_alerting_state_if_new_confs( + self, mock_ack, mock_remove_alerting_state, + mock_add_new_conf, mock_get_parent_id) -> None: + """ + In this test we will check that if new alert configs are received for + a new chain, the new config is added and the alerting state is cleared. + """ + mock_ack.return_value = None + mock_get_parent_id.return_value = self.test_parent_id + + self.test_system_alerter.rabbitmq.connect() + method = pika.spec.Basic.Deliver( + routing_key=self.test_configs_routing_key) + body = json.dumps(self.received_configurations) + self.test_system_alerter._process_configs(method, body) + + parsed_routing_key = self.test_configs_routing_key.split('.') + chain = parsed_routing_key[1] + ' ' + parsed_routing_key[2] + del self.received_configurations['DEFAULT'] + mock_add_new_conf.assert_called_once_with(chain, + self.received_configurations) + mock_get_parent_id.assert_called_once_with(chain) + mock_remove_alerting_state.assert_called_once_with(self.test_parent_id) + mock_ack.assert_called_once() + + @mock.patch.object(SystemAlertsConfigsFactory, "get_parent_id") + @mock.patch.object(SystemAlertsConfigsFactory, "remove_config") + @mock.patch.object(SystemAlertingFactory, "remove_chain_alerting_state") + @mock.patch.object(RabbitMQApi, "basic_ack") + def test_process_confs_removes_confs_and_alerting_state_if_conf_deleted( + self, mock_ack, mock_remove_alerting_state, mock_remove_config, + mock_get_parent_id) -> None: + """ + In this test we will check that if alert configurations are deleted for + a chain, the configs are removed and the alerting state is reset. Here + we will assume that the configurations exist + """ + mock_ack.return_value = None + mock_get_parent_id.return_value = self.test_parent_id + + self.test_system_alerter.rabbitmq.connect() + method = pika.spec.Basic.Deliver( + routing_key=self.test_configs_routing_key) + body = json.dumps({}) + self.test_system_alerter._process_configs(method, body) + + parsed_routing_key = self.test_configs_routing_key.split('.') + chain = parsed_routing_key[1] + ' ' + parsed_routing_key[2] + del self.received_configurations['DEFAULT'] + mock_get_parent_id.assert_called_once_with(chain) + mock_remove_alerting_state.assert_called_once_with(self.test_parent_id) + mock_remove_config.assert_called_once_with(chain) + mock_ack.assert_called_once() + + @mock.patch.object(SystemAlertsConfigsFactory, "add_new_config") + @mock.patch.object(SystemAlertsConfigsFactory, "get_parent_id") + @mock.patch.object(SystemAlertsConfigsFactory, "remove_config") + @mock.patch.object(SystemAlertingFactory, "remove_chain_alerting_state") + @mock.patch.object(RabbitMQApi, "basic_ack") + def test_process_confs_does_nothing_if_received_new_empty_configs( + self, mock_ack, mock_remove_alerting_state, mock_remove_conf, + mock_get_parent_id, mock_add_new_conf) -> None: + """ + In this test we will check that if empty alert configurations are + received for a new chain, the function does nothing. We will mock that + the config does not exist by making get_parent_id return None. + """ + mock_ack.return_value = None + mock_get_parent_id.return_value = None + + self.test_system_alerter.rabbitmq.connect() + method = pika.spec.Basic.Deliver( + routing_key=self.test_configs_routing_key) + body = json.dumps({}) + self.test_system_alerter._process_configs(method, body) + + parsed_routing_key = self.test_configs_routing_key.split('.') + chain = parsed_routing_key[1] + ' ' + parsed_routing_key[2] + mock_remove_alerting_state.assert_not_called() + mock_remove_conf.assert_not_called() + mock_add_new_conf.assert_not_called() + mock_get_parent_id.assert_called_once_with(chain) + mock_ack.assert_called_once() + + @mock.patch.object(SystemAlertsConfigsFactory, "get_parent_id") + @mock.patch.object(RabbitMQApi, "basic_ack") + def test_process_configs_acknowledges_received_data( + self, mock_ack, mock_get_parent_id) -> None: + """ + In this test we will check that if processing fails, the data is always + acknowledged. The case for when processing does not fail was performed + in each test above by checking that mock_ack has been called once. + """ + mock_ack.return_value = None + mock_get_parent_id.side_effect = Exception('test') - @parameterized.expand([ - ('open_file_descriptors', 'mock_ofd_increase'), - ('system_cpu_usage', 'mock_cpu_usage_increase'), - ('system_ram_usage', 'mock_ram_usage_increase'), - ('system_storage_usage', 'mock_storage_usage_increase'), - ]) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageDecreasedBelowThresholdAlert", - autospec=True) - def test_warning_alerts_disabled_increase_above_warning_threshold_no_alerts_occur( - self, metric_param, mock_param, mock_storage_usage_decrease, - mock_storage_usage_increase, mock_ram_usage_decrease, - mock_ram_usage_increase, mock_cpu_usage_decrease, - mock_cpu_usage_increase, mock_ofd_decrease, - mock_ofd_increase) -> None: - data_for_alerting = [] - data = self.data_received_initially_no_alert['result']['data'] - data[metric_param]['current'] = self.percent_usage + 46 - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter_warnings_disabled._create_state_for_system( - self.system_id) - self.test_system_alerter_warnings_disabled._process_results( - data, meta_data, data_for_alerting) - try: - mock_storage_usage_decrease.assert_not_called() - mock_ram_usage_decrease.assert_not_called() - mock_cpu_usage_decrease.assert_not_called() - mock_ofd_decrease.assert_not_called() - - eval(mock_param).assert_not_called() - self.assertEqual(0, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch.object(SystemAlerter, "_classify_alert") - def test_alerts_critical_alerts_disabled_metric_above_critical_threshold( - self, mock_classify_alert) -> None: - data_for_alerting = [] - data = self.data_received_initially_warning_alert['result']['data'] - meta_data = self.data_received_initially_warning_alert['result'][ - 'meta_data'] - self.test_system_alerter_critical_disabled._create_state_for_system( - self.system_id) - self.test_system_alerter_critical_disabled._process_results( - data, meta_data, data_for_alerting) - try: - self.assertEqual(4, mock_classify_alert.call_count) - self.assertEqual(0, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) + self.test_system_alerter.rabbitmq.connect() + method = pika.spec.Basic.Deliver( + routing_key=self.test_configs_routing_key) + body = json.dumps(self.received_configurations) - @parameterized.expand([ - ('open_file_descriptors', 'mock_ofd_increase'), - ('system_cpu_usage', 'mock_cpu_usage_increase'), - ('system_ram_usage', 'mock_ram_usage_increase'), - ('system_storage_usage', 'mock_storage_usage_increase'), - ]) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageDecreasedBelowThresholdAlert", - autospec=True) - def test_critical_alerts_disabled_increase_above_critical_threshold_warning_alert( - self, metric_param, mock_param, mock_storage_usage_decrease, - mock_storage_usage_increase, mock_ram_usage_decrease, - mock_ram_usage_increase, mock_cpu_usage_decrease, - mock_cpu_usage_increase, mock_ofd_decrease, - mock_ofd_increase) -> None: - data_for_alerting = [] - data = self.data_received_initially_no_alert['result']['data'] - data[metric_param]['current'] = self.percent_usage + 56 - data[metric_param]['previous'] = self.percent_usage + 46 - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter_critical_disabled._create_state_for_system( - self.system_id) - self.test_system_alerter_critical_disabled._process_results( - data, meta_data, data_for_alerting) - try: - eval(mock_param).assert_called_once_with( - self.system_name, data[metric_param]['current'], - self.warning, meta_data['last_monitored'], - self.warning, self.parent_id, self.system_id - ) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) + # Secondly test for when processing fails successful + self.test_system_alerter._process_configs(method, body) + mock_ack.assert_called_once() - @parameterized.expand([ - ('open_file_descriptors', 'mock_ofd_increase'), - ('system_cpu_usage', 'mock_cpu_usage_increase'), - ('system_ram_usage', 'mock_ram_usage_increase'), - ('system_storage_usage', 'mock_storage_usage_increase'), - ]) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageDecreasedBelowThresholdAlert", - autospec=True) - def test_increase_above_critical_first_time_critical_repeat_disabled( - self, metric_param, mock_param, mock_storage_usage_decrease, - mock_storage_usage_increase, mock_ram_usage_decrease, - mock_ram_usage_increase, mock_cpu_usage_decrease, - mock_cpu_usage_increase, mock_ofd_decrease, - mock_ofd_increase) -> None: - data_for_alerting = [] - data = self.data_received_initially_no_alert['result']['data'] - data[metric_param]['current'] = self.percent_usage + 56 - data[metric_param]['previous'] = self.percent_usage + 46 - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter_critical_repeat_disabled \ - ._create_state_for_system( - self.system_id) - self.test_system_alerter_critical_repeat_disabled._process_results( - data, meta_data, data_for_alerting) - try: - eval(mock_param).assert_called_once_with( - self.system_name, data[metric_param]['current'], - self.critical, meta_data['last_monitored'], - self.critical, self.parent_id, self.system_id - ) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) + def test_place_latest_data_on_queue_places_data_on_queue_correctly( + self) -> None: + test_data = ['data_1', 'data_2'] - @parameterized.expand([ - ('open_file_descriptors', 'mock_ofd_increase'), - ('system_cpu_usage', 'mock_cpu_usage_increase'), - ('system_ram_usage', 'mock_ram_usage_increase'), - ('system_storage_usage', 'mock_storage_usage_increase'), - ]) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageDecreasedBelowThresholdAlert", - autospec=True) - def test_increase_above_critical_second_time_critical_repeat_disabled( - self, metric_param, mock_param, mock_storage_usage_decrease, - mock_storage_usage_increase, mock_ram_usage_decrease, - mock_ram_usage_increase, mock_cpu_usage_decrease, - mock_cpu_usage_increase, mock_ofd_decrease, - mock_ofd_increase) -> None: - data_for_alerting = [] - data = self.data_received_initially_no_alert['result']['data'] - data[metric_param]['current'] = self.percent_usage + 56 - data[metric_param]['previous'] = self.percent_usage + 46 - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter_critical_repeat_disabled \ - ._create_state_for_system( - self.system_id) - self.test_system_alerter_critical_repeat_disabled._process_results( - data, meta_data, data_for_alerting) - - # process again to confirm that when critical_repeat is disabled, no - # critical alerts are sent even if the repeat time passes. - old_last_monitored = meta_data['last_monitored'] - meta_data['last_monitored'] = \ - old_last_monitored + self.critical_repeat_seconds - self.test_system_alerter_critical_repeat_disabled._process_results( - data, meta_data, data_for_alerting) - try: - eval(mock_param).assert_called_once_with( - self.system_name, data[metric_param]['current'], - self.critical, old_last_monitored, - self.critical, self.parent_id, self.system_id - ) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) + self.assertTrue(self.test_system_alerter.publishing_queue.empty()) - @parameterized.expand([ - ('open_file_descriptors', 'mock_ofd_increase'), - ('system_cpu_usage', 'mock_cpu_usage_increase'), - ('system_ram_usage', 'mock_ram_usage_increase'), - ('system_storage_usage', 'mock_storage_usage_increase'), - ]) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".OpenFileDescriptorsDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemCPUUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemRAMUsageDecreasedBelowThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageIncreasedAboveThresholdAlert", - autospec=True) - @mock.patch( - "src.alerter.alerters.system" - ".SystemStorageUsageDecreasedBelowThresholdAlert", - autospec=True) - def test_critical_alerts_and_warning_alerts_disabled_increase_above_critical_threshold_no_alerts( - self, metric_param, mock_param, mock_storage_usage_decrease, - mock_storage_usage_increase, mock_ram_usage_decrease, - mock_ram_usage_increase, mock_cpu_usage_decrease, - mock_cpu_usage_increase, mock_ofd_decrease, - mock_ofd_increase) -> None: - data_for_alerting = [] - data = self.data_received_initially_no_alert['result']['data'] - data[metric_param]['current'] = self.percent_usage + 56 - data[metric_param]['previous'] = self.percent_usage + 46 - meta_data = self.data_received_initially_no_alert['result']['meta_data'] - self.test_system_alerter_all_disabled._create_state_for_system( - self.system_id) - self.test_system_alerter_all_disabled._process_results( - data, meta_data, data_for_alerting) - try: - eval(mock_param).assert_not_called() - except AssertionError as e: - self.fail("Test failed: {}".format(e)) + expected_data_1 = { + 'exchange': ALERT_EXCHANGE, + 'routing_key': SYSTEM_ALERT_ROUTING_KEY, + 'data': 'data_1', + 'properties': pika.BasicProperties(delivery_mode=2), + 'mandatory': True + } + expected_data_2 = { + 'exchange': ALERT_EXCHANGE, + 'routing_key': SYSTEM_ALERT_ROUTING_KEY, + 'data': 'data_2', + 'properties': pika.BasicProperties(delivery_mode=2), + 'mandatory': True + } + self.test_system_alerter._place_latest_data_on_queue(test_data) + self.assertEqual(2, + self.test_system_alerter.publishing_queue.qsize()) + self.assertEqual(expected_data_1, + self.test_system_alerter.publishing_queue.get()) + self.assertEqual(expected_data_2, + self.test_system_alerter.publishing_queue.get()) - @mock.patch.object(SystemAlerter, "_classify_alert") - def test_alerts_all_alerts_disabled_metric_above_critical_threshold_and_warning_threshold( - self, mock_classify_alert) -> None: + def test_place_latest_data_on_queue_removes_old_data_if_full_then_places( + self) -> None: + # First fill the queue with the same data + test_data_1 = ['data_1'] + for i in range(self.test_queue_size): + self.test_system_alerter._place_latest_data_on_queue(test_data_1) + + # Now fill the queue with the second piece of data, and confirm that + # now only the second piece of data prevails. + test_data_2 = ['data_2'] + for i in range(self.test_queue_size): + self.test_system_alerter._place_latest_data_on_queue(test_data_2) + + for i in range(self.test_queue_size): + expected_data = { + 'exchange': ALERT_EXCHANGE, + 'routing_key': SYSTEM_ALERT_ROUTING_KEY, + 'data': 'data_2', + 'properties': pika.BasicProperties(delivery_mode=2), + 'mandatory': True + } + self.assertEqual(expected_data, + self.test_system_alerter.publishing_queue.get()) + + @mock.patch.object(SystemAlertingFactory, "classify_downtime_alert") + @mock.patch.object(SystemAlertingFactory, "classify_error_alert") + @mock.patch.object(SystemAlertingFactory, "classify_no_change_in_alert") + @mock.patch.object(SystemAlertingFactory, + "classify_thresholded_time_window_alert") + @mock.patch.object(SystemAlertingFactory, + "classify_thresholded_in_time_period_alert") + @mock.patch.object(SystemAlertingFactory, + "classify_conditional_alert") + @mock.patch.object(SystemAlertingFactory, + "classify_thresholded_alert_reverse") + def test_process_result_does_nothing_if_config_not_received( + self, mock_reverse, mock_cond_alert, mock_thresh_per_alert, + mock_thresh_win_alert, mock_no_change_alert, + mock_error_alert, mock_downtime_alert) -> None: + """ + In this test we will check that no classification function is called + if data has been received for a system who's associated alerts + configuration is not received yet. + """ data_for_alerting = [] - data = self.data_received_initially_critical_alert['result']['data'] - meta_data = self.data_received_initially_critical_alert['result'][ - 'meta_data'] - self.test_system_alerter_all_disabled._create_state_for_system( - self.system_id) - self.test_system_alerter_all_disabled._process_results( - data, meta_data, data_for_alerting) - try: - self.assertEqual(0, mock_classify_alert.call_count) - self.assertEqual(0, len(data_for_alerting)) - except AssertionError as e: - self.fail("Test failed: {}".format(e)) - - """ - ###################### Tests using RabbitMQ ####################### - """ + self.test_system_alerter._process_result(self.test_result_data, + data_for_alerting) + + mock_reverse.assert_not_called() + mock_cond_alert.assert_not_called() + mock_thresh_per_alert.assert_not_called() + mock_thresh_win_alert.assert_not_called() + mock_no_change_alert.assert_not_called() + mock_error_alert.assert_not_called() + mock_downtime_alert.assert_not_called() + + @mock.patch.object(SystemAlertingFactory, "classify_thresholded_alert") + @mock.patch.object(SystemAlertingFactory, "classify_downtime_alert") + @mock.patch.object(SystemAlertingFactory, "classify_error_alert") + @mock.patch.object(SystemAlertingFactory, "classify_no_change_in_alert") + @mock.patch.object(SystemAlertingFactory, + "classify_thresholded_time_window_alert") + @mock.patch.object(SystemAlertingFactory, + "classify_thresholded_in_time_period_alert") + @mock.patch.object(SystemAlertingFactory, + "classify_conditional_alert") + @mock.patch.object(SystemAlertingFactory, + "classify_thresholded_alert_reverse") + def test_process_result_does_not_classify_if_metrics_disabled( + self, mock_reverse, mock_cond_alert, mock_thresh_per_alert, + mock_thresh_win_alert, mock_no_change_alert, mock_error_alert, + mock_downtime_alert, mock_thresh_alert) -> None: + """ + In this test we will check that if a metric is disabled from the config, + there will be no alert classification for the associated alerts. Note + that for easier testing we will set every metric to be disabled. Again, + the only classification which would happen is for the error alerts. + """ + # Add configs for the test data + parsed_routing_key = self.test_configs_routing_key.split('.') + chain = parsed_routing_key[1] + ' ' + parsed_routing_key[2] + del self.received_configurations['DEFAULT'] + + # Set each metric to disabled + for index, config in self.received_configurations.items(): + config['enabled'] = 'False' + self.test_configs_factory.add_new_config( + chain, self.received_configurations) + + data_for_alerting = [] + self.test_system_alerter._process_result(self.test_result_data, + data_for_alerting) + + mock_reverse.assert_not_called() + mock_cond_alert.assert_not_called() + mock_thresh_per_alert.assert_not_called() + mock_thresh_win_alert.assert_not_called() + mock_no_change_alert.assert_not_called() + mock_downtime_alert.assert_not_called() + mock_thresh_alert.assert_not_called() + + calls = mock_error_alert.call_args_list + self.assertEqual(2, mock_error_alert.call_count) + call_1 = call( + InvalidUrlException.code, system_alerts.InvalidUrlAlert, + system_alerts.ValidUrlAlert, data_for_alerting, + self.test_parent_id, self.test_system_id, self.test_system_name, + self.test_last_monitored, MetricCode.InvalidUrl.value, "", + "URL is now valid!.") + self.assertTrue(call_1 in calls) + call_2 = call( + MetricNotFoundException.code, + system_alerts.MetricNotFoundErrorAlert, + system_alerts.MetricFoundAlert, data_for_alerting, + self.test_parent_id, self.test_system_id, self.test_system_name, + self.test_last_monitored, MetricCode.MetricNotFound.value, "", + "Metrics have been found!.") + self.assertTrue(call_2 in calls) + + @mock.patch.object(SystemAlertingFactory, "classify_downtime_alert") + @mock.patch.object(SystemAlertingFactory, "classify_error_alert") + @mock.patch.object(SystemAlertingFactory, "classify_no_change_in_alert") + @mock.patch.object(SystemAlertingFactory, + "classify_thresholded_alert") + @mock.patch.object(SystemAlertingFactory, + "classify_thresholded_in_time_period_alert") + @mock.patch.object(SystemAlertingFactory, + "classify_conditional_alert") + @mock.patch.object(SystemAlertingFactory, + "classify_thresholded_alert_reverse") + def test_process_result_classifies_correctly_if_data_valid( + self, mock_reverse, mock_cond_alert, mock_thresh_per_alert, + mock_thresh_alert, mock_no_change_alert, + mock_error_alert, mock_downtime_alert) -> None: + """ + In this test we will check that the correct classification functions are + called correctly by the process_result function. Note that + the actual logic for these classification functions was tested in the + alert factory class. + """ + # Add configs for the test data + parsed_routing_key = self.test_configs_routing_key.split('.') + chain = parsed_routing_key[1] + ' ' + parsed_routing_key[2] + del self.received_configurations['DEFAULT'] + self.test_configs_factory.add_new_config( + chain, self.received_configurations) + configs = self.test_configs_factory.configs[chain] + + data_for_alerting = [] + self.test_system_alerter._process_result(self.test_result_data, + data_for_alerting) + + calls = mock_error_alert.call_args_list + self.assertEqual(2, mock_error_alert.call_count) + call_1 = call( + InvalidUrlException.code, system_alerts.InvalidUrlAlert, + system_alerts.ValidUrlAlert, data_for_alerting, + self.test_parent_id, self.test_system_id, self.test_system_name, + self.test_last_monitored, MetricCode.InvalidUrl.value, "", + "URL is now valid!.") + self.assertTrue(call_1 in calls) + call_2 = call( + MetricNotFoundException.code, + system_alerts.MetricNotFoundErrorAlert, + system_alerts.MetricFoundAlert, data_for_alerting, + self.test_parent_id, self.test_system_id, self.test_system_name, + self.test_last_monitored, MetricCode.MetricNotFound.value, "", + "Metrics have been found!.") + self.assertTrue(call_2 in calls) + + calls = mock_downtime_alert.call_args_list + self.assertEqual(1, mock_downtime_alert.call_count) + call_1 = call( + None, configs.system_is_down, system_alerts.SystemWentDownAtAlert, + system_alerts.SystemStillDownAlert, + system_alerts.SystemBackUpAgainAlert, + data_for_alerting, self.test_parent_id, self.test_system_id, + MetricCode.SystemIsDown.value, + self.test_system_name, self.test_last_monitored) + self.assertTrue(call_1 in calls) + + calls = mock_thresh_alert.call_args_list + self.assertEqual(4, mock_thresh_alert.call_count) + call_1 = call( + self.test_result_data['data']['open_file_descriptors']['current'], + configs.open_file_descriptors, + system_alerts.OpenFileDescriptorsIncreasedAboveThresholdAlert, + system_alerts.OpenFileDescriptorsDecreasedBelowThresholdAlert, + data_for_alerting, self.test_parent_id, self.test_system_id, + MetricCode.OpenFileDescriptorsThreshold.value, + self.test_system_name, self.test_last_monitored) + self.assertTrue(call_1 in calls) + call_2 = call( + self.test_result_data['data']['system_cpu_usage']['current'], + configs.system_cpu_usage, + system_alerts.SystemCPUUsageIncreasedAboveThresholdAlert, + system_alerts.SystemCPUUsageDecreasedBelowThresholdAlert, + data_for_alerting, self.test_parent_id, self.test_system_id, + MetricCode.SystemCPUUsageThreshold.value, + self.test_system_name, self.test_last_monitored) + self.assertTrue(call_2 in calls) + call_3 = call( + self.test_result_data['data']['system_ram_usage']['current'], + configs.system_ram_usage, + system_alerts.SystemRAMUsageIncreasedAboveThresholdAlert, + system_alerts.SystemRAMUsageDecreasedBelowThresholdAlert, + data_for_alerting, self.test_parent_id, self.test_system_id, + MetricCode.SystemRAMUsageThreshold.value, + self.test_system_name, self.test_last_monitored) + self.assertTrue(call_3 in calls) + call_4 = call( + self.test_result_data['data']['system_storage_usage']['current'], + configs.system_storage_usage, + system_alerts.SystemStorageUsageIncreasedAboveThresholdAlert, + system_alerts.SystemStorageUsageDecreasedBelowThresholdAlert, + data_for_alerting, self.test_parent_id, self.test_system_id, + MetricCode.SystemStorageUsageThreshold.value, + self.test_system_name, self.test_last_monitored) + self.assertTrue(call_4 in calls) + + mock_no_change_alert.assert_not_called() + mock_cond_alert.assert_not_called() + mock_reverse.assert_not_called() + mock_thresh_per_alert.assert_not_called() + + @mock.patch.object(SystemAlertingFactory, "classify_downtime_alert") + @mock.patch.object(SystemAlertingFactory, "classify_error_alert") + def test_process_error_classifies_correctly_if_data_valid( + self, mock_error_alert, mock_downtime_alert) -> None: + """ + In this test we will check that if we received an InvalidURL + Exception then we should generate an alert for it. + """ + parsed_routing_key = self.test_configs_routing_key.split('.') + chain = parsed_routing_key[1] + ' ' + parsed_routing_key[2] + del self.received_configurations['DEFAULT'] + self.test_configs_factory.add_new_config( + chain, self.received_configurations) + configs = self.test_configs_factory.configs[chain] + + data_for_alerting = [] + self.test_system_alerter._process_error( + self.test_system_down_error, data_for_alerting) + + calls = mock_error_alert.call_args_list + self.assertEqual(2, mock_error_alert.call_count) + call_1 = call( + InvalidUrlException.code, system_alerts.InvalidUrlAlert, + system_alerts.ValidUrlAlert, data_for_alerting, self.test_parent_id, + self.test_system_id, self.test_system_name, + self.test_last_monitored, MetricCode.InvalidUrl.value, + self.test_system_is_down_exception.message, + "URL is now valid!", self.test_system_is_down_exception.code) + self.assertTrue(call_1 in calls) + call_2 = call( + MetricNotFoundException.code, + system_alerts.MetricNotFoundErrorAlert, + system_alerts.MetricFoundAlert, data_for_alerting, + self.test_parent_id, self.test_system_id, self.test_system_name, + self.test_last_monitored, + MetricCode.MetricNotFound.value, + self.test_system_is_down_exception.message, + "Metrics have been found!", + self.test_system_is_down_exception.code) + self.assertTrue(call_2 in calls) + + meta_data = self.test_system_down_error['meta_data'] + mock_downtime_alert.assert_called_once_with( + self.test_system_down_error['data']['went_down_at']['current'], + configs.system_is_down, system_alerts.SystemWentDownAtAlert, + system_alerts.SystemStillDownAlert, + system_alerts.SystemBackUpAgainAlert, data_for_alerting, + meta_data['system_parent_id'], meta_data['system_id'], + MetricCode.SystemIsDown.value, meta_data['system_name'], + meta_data['time'] + ) - def test_initialise_rabbit_initialises_queues(self) -> None: - self.test_system_alerter._initialise_rabbitmq() - try: - self.rabbitmq.connect() - self.rabbitmq.queue_declare(self.queue_used, passive=True) - except pika.exceptions.ConnectionClosedByBroker: - self.fail("Queue {} was not declared".format(self.queue_used)) + @mock.patch.object(SystemAlerter, "_place_latest_data_on_queue") + @mock.patch.object(RabbitMQApi, "basic_ack") + def test_process_transformed_data_does_not_place_alerts_on_queue_if_none( + self, mock_basic_ack, mock_place_on_queue) -> None: + # We will not be adding configs so that no alerts are generated - def test_initialise_rabbit_initialises_exchanges(self) -> None: + # Declare some fields for the process_transformed_data function self.test_system_alerter._initialise_rabbitmq() + method = pika.spec.Basic.Deliver( + routing_key=SYSTEM_TRANSFORMED_DATA_ROUTING_KEY) + body = json.dumps(self.transformed_data_example_result) + self.test_system_alerter._process_transformed_data(method, body) - try: - self.rabbitmq.connect() - self.rabbitmq.exchange_declare(ALERT_EXCHANGE, passive=True) - except pika.exceptions.ConnectionClosedByBroker: - self.fail("Exchange {} was not declared".format(ALERT_EXCHANGE)) - - def test_send_warning_alerts_correctly( - self) -> None: - try: - self.test_system_alerter._initialise_rabbitmq() - self.test_system_alerter.rabbitmq.queue_delete( - self.target_queue_used) - self.test_system_alerter.rabbitmq.exchange_declare( - HEALTH_CHECK_EXCHANGE, TOPIC, False, True, False, False) - res = self.test_system_alerter.rabbitmq.queue_declare( - queue=self.target_queue_used, durable=True, exclusive=False, - auto_delete=False, passive=False - ) - self.assertEqual(0, res.method.message_count) - self.test_system_alerter.rabbitmq.queue_bind( - queue=self.target_queue_used, exchange=ALERT_EXCHANGE, - routing_key=self.output_routing_key) - - self.test_system_alerter.rabbitmq.basic_publish_confirm( - exchange=ALERT_EXCHANGE, - routing_key=self.output_routing_key, - body=self.alert.alert_data, is_body_dict=True, - properties=pika.BasicProperties(delivery_mode=2), - mandatory=True) - - res = self.test_system_alerter.rabbitmq.queue_declare( - queue=self.target_queue_used, durable=True, exclusive=False, - auto_delete=False, passive=True - ) - self.assertEqual(1, res.method.message_count) - - _, _, body = self.test_system_alerter.rabbitmq.basic_get( - self.target_queue_used) - # For some reason during the conversion [] are swapped to () - self.assertEqual(json.loads(json.dumps(self.alert.alert_data)), - json.loads(body)) - - self.test_system_alerter.rabbitmq.queue_purge( - self.target_queue_used) - self.test_system_alerter.rabbitmq.queue_delete( - self.target_queue_used) - self.test_system_alerter.rabbitmq.exchange_delete(ALERT_EXCHANGE) - self.test_system_alerter.rabbitmq.exchange_delete( - HEALTH_CHECK_EXCHANGE) - self.test_system_alerter.rabbitmq.disconnect() - except Exception as e: - self.fail("Test failed: {}".format(e)) - - # Same test that is in monitors tests - def test_send_heartbeat_sends_a_heartbeat_correctly(self) -> None: - try: - self.test_system_alerter._initialise_rabbitmq() - self.test_system_alerter.rabbitmq.exchange_declare( - HEALTH_CHECK_EXCHANGE, TOPIC, False, True, False, False) - - self.test_system_alerter.rabbitmq.queue_delete(self.heartbeat_queue) - - res = self.test_system_alerter.rabbitmq.queue_declare( - queue=self.heartbeat_queue, durable=True, exclusive=False, - auto_delete=False, passive=False - ) - self.assertEqual(0, res.method.message_count) - self.test_system_alerter.rabbitmq.queue_bind( - queue=self.heartbeat_queue, exchange=HEALTH_CHECK_EXCHANGE, - routing_key=HEARTBEAT_OUTPUT_WORKER_ROUTING_KEY) - self.test_system_alerter._send_heartbeat(self.heartbeat_test) - - res = self.test_system_alerter.rabbitmq.queue_declare( - queue=self.heartbeat_queue, durable=True, exclusive=False, - auto_delete=False, passive=True - ) - self.assertEqual(1, res.method.message_count) - - _, _, body = self.test_system_alerter.rabbitmq.basic_get( - self.heartbeat_queue) - self.assertEqual(self.heartbeat_test, json.loads(body)) - - self.test_system_alerter.rabbitmq.queue_purge(self.heartbeat_queue) - self.test_system_alerter.rabbitmq.queue_delete(self.heartbeat_queue) - self.test_system_alerter.rabbitmq.exchange_delete( - HEALTH_CHECK_EXCHANGE) - self.test_system_alerter.rabbitmq.disconnect() - except Exception as e: - self.fail("Test failed: {}".format(e)) + mock_basic_ack.assert_called_once() + mock_place_on_queue.assert_not_called() - """ - Testing _process_data using RabbitMQ - """ - - @mock.patch("src.alerter.alerters.system.SystemAlerter._process_results") - @mock.patch( - "src.alerter.alerters.system.SystemAlerter._create_state_for_system") + @mock.patch.object(SystemAlerter, "_process_result") @mock.patch.object(RabbitMQApi, "basic_ack") - def test_process_result_data_no_alerts( - self, mock_ack, mock_create_state_for_system, - mock_process_results) -> None: - - mock_ack.return_value = None + def test_process_transformed_data_does_not_raise_processing_error( + self, mock_basic_ack, mock_process_result) -> None: + """ + In this test we will generate an exception from one of the processing + functions to see if an exception is raised. + """ + mock_process_result.side_effect = self.test_system_is_down_exception + # Declare some fields for the process_transformed_data function + self.test_system_alerter._initialise_rabbitmq() + method = pika.spec.Basic.Deliver( + routing_key=SYSTEM_TRANSFORMED_DATA_ROUTING_KEY) + body = json.dumps(self.transformed_data_example_result) try: - self.test_system_alerter.rabbitmq.connect() - blocking_channel = self.test_system_alerter.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=self.input_routing_key) - body = json.dumps(self.data_received_initially_no_alert) - properties = pika.spec.BasicProperties() - self.test_system_alerter._process_data(blocking_channel, method, - properties, body) - mock_create_state_for_system.assert_called_with(self.system_id) - mock_process_results.assert_called_with( - self.data_received_initially_no_alert['result']['data'], - self.data_received_initially_no_alert['result']['meta_data'], - [] - ) - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.SystemAlerter._process_errors") - @mock.patch( - "src.alerter.alerters.system.SystemAlerter._create_state_for_system") - @mock.patch.object(RabbitMQApi, "basic_ack") - def test_process_error_data_no_alerts( - self, mock_ack, mock_create_state_for_system, - mock_process_errors) -> None: - - mock_ack.return_value = None + self.test_system_alerter._process_transformed_data(method, body) + except PANICException as e: + self.fail('Did not expect {} to be raised.'.format(e)) - try: - self.test_system_alerter.rabbitmq.connect() - blocking_channel = self.test_system_alerter.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=self.input_routing_key) - body = json.dumps(self.data_received_error_data) - properties = pika.spec.BasicProperties() - self.test_system_alerter._process_data(blocking_channel, method, - properties, body) - mock_create_state_for_system.assert_called_with(self.system_id) - mock_process_errors.assert_called_with( - self.data_received_error_data['error'], - [] - ) - except Exception as e: - self.fail("Test failed: {}".format(e)) + mock_basic_ack.assert_called_once() - @freeze_time("2012-01-01") - @mock.patch("src.alerter.alerters.system.SystemAlerter._send_heartbeat") - @mock.patch("src.alerter.alerters.system.SystemAlerter._process_results") - @mock.patch( - "src.alerter.alerters.system.SystemAlerter._create_state_for_system") + @mock.patch.object(SystemAlerter, "_send_data") + @mock.patch.object(SystemAlerter, "_process_result") @mock.patch.object(RabbitMQApi, "basic_ack") - def test_process_result_data_send_hb_no_proc_error( - self, mock_ack, mock_create_state_for_system, - mock_process_results, mock_send_heartbeat) -> None: + def test_process_transformed_data_attempts_to_send_data_from_queue( + self, mock_basic_ack, mock_process_result, + mock_send_data) -> None: + # Add configs so that the data can be classified. The test data used + # will generate an alert because it will obey the thresholds. + parsed_routing_key = self.test_configs_routing_key.split('.') + chain = parsed_routing_key[1] + ' ' + parsed_routing_key[2] + del self.received_configurations['DEFAULT'] + self.test_configs_factory.add_new_config( + chain, self.received_configurations) + + # First do the test for when there are no processing errors + self.test_system_alerter._initialise_rabbitmq() + method = pika.spec.Basic.Deliver( + routing_key=SYSTEM_TRANSFORMED_DATA_ROUTING_KEY) + body = json.dumps(self.transformed_data_example_result) + self.test_system_alerter._process_transformed_data(method, body) - mock_ack.return_value = None - mock_create_state_for_system.return_value = None - mock_process_results.return_value = None + mock_basic_ack.assert_called_once() + mock_send_data.assert_called_once() - try: - self.test_system_alerter.rabbitmq.connect() - blocking_channel = self.test_system_alerter.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=self.input_routing_key) - body = json.dumps(self.data_received_initially_no_alert) - properties = pika.spec.BasicProperties() - self.test_system_alerter._process_data(blocking_channel, method, - properties, body) - heartbeat_test = { - 'component_name': self.alerter_name, - 'is_alive': True, - 'timestamp': datetime.datetime(2012, 1, 1).timestamp() - } - mock_send_heartbeat.assert_called_with(heartbeat_test) - except Exception as e: - self.fail("Test failed: {}".format(e)) + # Now do the test for when there are processing errors + mock_basic_ack.reset_mock() + mock_send_data.reset_mock() + mock_process_result.side_effect = self.test_system_is_down_exception - @freeze_time("2012-01-01") - @mock.patch("src.alerter.alerters.system.SystemAlerter._send_heartbeat") - @mock.patch("src.alerter.alerters.system.SystemAlerter._process_errors") - @mock.patch( - "src.alerter.alerters.system.SystemAlerter._create_state_for_system") - @mock.patch.object(RabbitMQApi, "basic_ack") - def test_process_error_data_send_hb_no_proc_error( - self, mock_ack, mock_create_state_for_system, - mock_process_errors, mock_send_heartbeat) -> None: + # Declare some fields for the process_transformed_data function + self.test_system_alerter._process_transformed_data(method, body) - mock_ack.return_value = None - mock_create_state_for_system.return_value = None - mock_process_errors.return_value = None - try: - self.test_system_alerter.rabbitmq.connect() - blocking_channel = self.test_system_alerter.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=self.input_routing_key) - body = json.dumps(self.data_received_error_data) - properties = pika.spec.BasicProperties() - self.test_system_alerter._process_data(blocking_channel, method, - properties, body) - heartbeat_test = { - 'component_name': self.alerter_name, - 'is_alive': True, - 'timestamp': datetime.datetime(2012, 1, 1).timestamp() - } - mock_send_heartbeat.assert_called_with(heartbeat_test) - except Exception as e: - self.fail("Test failed: {}".format(e)) + mock_basic_ack.assert_called_once() + mock_send_data.assert_called_once() @freeze_time("2012-01-01") - @mock.patch("src.alerter.alerters.system.SystemAlerter._send_heartbeat") - @mock.patch("src.alerter.alerters.system.SystemAlerter._process_results") - @mock.patch( - "src.alerter.alerters.system.SystemAlerter._create_state_for_system") + @mock.patch.object(SystemAlerter, "_send_data") + @mock.patch.object(SystemAlerter, "_send_heartbeat") @mock.patch.object(RabbitMQApi, "basic_ack") - def test_process_result_data_do_not_send_hb_on_proc_error_bad_routing_key( - self, mock_ack, mock_create_state_for_system, - mock_process_results, mock_send_heartbeat) -> None: + def test_process_transformed_data_sends_hb_if_no_processing_errors( + self, mock_basic_ack, mock_send_hb, mock_send_data) -> None: + # To avoid sending data + mock_send_data.return_value = None + + # Add configs so that the data can be classified. The test data used + # will generate an alert because it will obey the thresholds. + parsed_routing_key = self.test_configs_routing_key.split('.') + chain = parsed_routing_key[1] + ' ' + parsed_routing_key[2] + del self.received_configurations['DEFAULT'] + self.test_configs_factory.add_new_config( + chain, self.received_configurations) - mock_ack.return_value = None - mock_create_state_for_system.return_value = None - mock_process_results.return_value = None - - try: - self.test_system_alerter.rabbitmq.connect() - blocking_channel = self.test_system_alerter.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=self.bad_output_routing_key) - body = json.dumps(self.data_received_initially_no_alert) - properties = pika.spec.BasicProperties() - self.test_system_alerter._process_data(blocking_channel, method, - properties, body) - mock_send_heartbeat.assert_not_called() - except Exception as e: - self.fail("Test failed: {}".format(e)) + self.test_system_alerter._initialise_rabbitmq() + method = pika.spec.Basic.Deliver( + routing_key=SYSTEM_TRANSFORMED_DATA_ROUTING_KEY) + body = json.dumps(self.transformed_data_example_result) + self.test_system_alerter._process_transformed_data(method, body) + + mock_basic_ack.assert_called_once() + test_hb = { + 'component_name': self.test_alerter_name, + 'is_alive': True, + 'timestamp': datetime.datetime.now().timestamp() + } + mock_send_hb.assert_called_once_with(test_hb) @freeze_time("2012-01-01") - @mock.patch("src.alerter.alerters.system.SystemAlerter._send_heartbeat") - @mock.patch("src.alerter.alerters.system.SystemAlerter._process_errors") - @mock.patch( - "src.alerter.alerters.system.SystemAlerter._create_state_for_system") - @mock.patch.object(RabbitMQApi, "basic_ack") - def test_process_error_data_do_not_send_hb_on_proc_error_bad_routing_key( - self, mock_ack, mock_create_state_for_system, - mock_process_errors, mock_send_heartbeat) -> None: - - mock_ack.return_value = None - mock_create_state_for_system.return_value = None - mock_process_errors.return_value = None - - try: - self.test_system_alerter.rabbitmq.connect() - blocking_channel = self.test_system_alerter.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=self.bad_output_routing_key) - body = json.dumps(self.data_received_error_data) - properties = pika.spec.BasicProperties() - self.test_system_alerter._process_data(blocking_channel, method, - properties, body) - mock_send_heartbeat.assert_not_called() - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.SystemAlerter._send_data") - @mock.patch("src.alerter.alerters.system.SystemAlerter._process_results") - @mock.patch( - "src.alerter.alerters.system.SystemAlerter._create_state_for_system") - @mock.patch.object(RabbitMQApi, "basic_ack") - def test_process_result_data_send_data_called( - self, mock_ack, mock_create_state_for_system, - mock_process_results, mock_send_data) -> None: - - mock_ack.return_value = None - mock_create_state_for_system.return_value = None - mock_process_results.return_value = None - - try: - self.test_system_alerter.rabbitmq.connect() - blocking_channel = self.test_system_alerter.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=self.input_routing_key) - body = json.dumps(self.data_received_initially_no_alert) - properties = pika.spec.BasicProperties() - self.test_system_alerter._process_data(blocking_channel, method, - properties, body) - mock_send_data.assert_called_once() - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.SystemAlerter._send_data") - @mock.patch("src.alerter.alerters.system.SystemAlerter._process_errors") - @mock.patch( - "src.alerter.alerters.system.SystemAlerter._create_state_for_system") + @mock.patch.object(SystemAlerter, "_process_result") + @mock.patch.object(SystemAlerter, "_send_data") + @mock.patch.object(SystemAlerter, "_send_heartbeat") @mock.patch.object(RabbitMQApi, "basic_ack") - def test_process_error_data_send_data_called( - self, mock_ack, mock_create_state_for_system, - mock_process_errors, mock_send_data) -> None: + def test_process_transformed_data_does_not_send_hb_if_processing_error( + self, mock_basic_ack, mock_send_hb, mock_send_data, + mock_process_result) -> None: + # To avoid sending data + mock_send_data.return_value = None - mock_ack.return_value = None - mock_create_state_for_system.return_value = None - mock_process_errors.return_value = None + # Generate error in processing + mock_process_result.side_effect = self.test_system_is_down_exception - try: - self.test_system_alerter.rabbitmq.connect() - blocking_channel = self.test_system_alerter.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=self.input_routing_key) - body = json.dumps(self.data_received_error_data) - properties = pika.spec.BasicProperties() - self.test_system_alerter._process_data(blocking_channel, method, - properties, body) - mock_send_data.assert_called_once() - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.SystemAlerter._process_results") - @mock.patch( - "src.alerter.alerters.system.SystemAlerter._create_state_for_system") - @mock.patch.object(RabbitMQApi, "basic_ack") - def test_process_result_data_not_processed_bad_routing_key( - self, mock_ack, mock_create_state_for_system, - mock_process_results) -> None: - mock_ack.return_value = None - try: - self.test_system_alerter.rabbitmq.connect() - blocking_channel = self.test_system_alerter.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=self.bad_output_routing_key) - body = json.dumps(self.data_received_initially_no_alert) - properties = pika.spec.BasicProperties() - self.test_system_alerter._process_data(blocking_channel, method, - properties, body) - mock_create_state_for_system.assert_not_called() - mock_process_results.assert_not_called() - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.SystemAlerter._process_errors") - @mock.patch( - "src.alerter.alerters.system.SystemAlerter._create_state_for_system") - @mock.patch.object(RabbitMQApi, "basic_ack") - def test_process_error_data_not_processed_bad_routing_key( - self, mock_ack, mock_create_state_for_system, - mock_process_errors) -> None: + self.test_system_alerter._initialise_rabbitmq() + method = pika.spec.Basic.Deliver( + routing_key=SYSTEM_TRANSFORMED_DATA_ROUTING_KEY) + body = json.dumps(self.transformed_data_example_result) + self.test_system_alerter._process_transformed_data(method, body) - mock_ack.return_value = None + mock_basic_ack.assert_called_once() + mock_send_hb.assert_not_called() - try: - self.test_system_alerter.rabbitmq.connect() - blocking_channel = self.test_system_alerter.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=self.bad_output_routing_key) - body = json.dumps(self.data_received_error_data) - properties = pika.spec.BasicProperties() - self.test_system_alerter._process_data(blocking_channel, method, - properties, body) - mock_create_state_for_system.assert_not_called() - mock_process_errors.assert_not_called() - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.SystemAlerter._process_results") - @mock.patch( - "src.alerter.alerters.system.SystemAlerter._create_state_for_system") - @mock.patch.object(RabbitMQApi, "basic_ack") - def test_process_result_data_not_processed_bad_data_received( - self, mock_ack, mock_create_state_for_system, - mock_process_results) -> None: - mock_ack.return_value = None - try: - self.test_system_alerter.rabbitmq.connect() - blocking_channel = self.test_system_alerter.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=self.bad_output_routing_key) - del self.data_received_initially_no_alert['result']['data'] - body = json.dumps(self.data_received_initially_no_alert) - properties = pika.spec.BasicProperties() - self.test_system_alerter._process_data(blocking_channel, method, - properties, body) - mock_create_state_for_system.assert_not_called() - mock_process_results.assert_not_called() - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.alerters.system.SystemAlerter._process_errors") - @mock.patch( - "src.alerter.alerters.system.SystemAlerter._create_state_for_system") + @parameterized.expand([ + (pika.exceptions.AMQPConnectionError, + pika.exceptions.AMQPConnectionError('test'),), + (pika.exceptions.AMQPChannelError, + pika.exceptions.AMQPChannelError('test'),), + (Exception, Exception('test'),), + ]) + @mock.patch.object(SystemAlerter, "_send_data") @mock.patch.object(RabbitMQApi, "basic_ack") - def test_process_error_data_not_processed_bad_data_received( - self, mock_ack, mock_create_state_for_system, - mock_process_errors) -> None: + def test_process_transformed_data_raises_unexpected_exception( + self, exception_class, exception_instance, mock_basic_ack, + mock_send_data) -> None: + # We will generate the error from the send_data fn + mock_send_data.side_effect = exception_instance + + # Add configs so that the data can be classified. The test data used + # will generate an alert because it will obey the thresholds. + parsed_routing_key = self.test_configs_routing_key.split('.') + chain = parsed_routing_key[1] + ' ' + parsed_routing_key[2] + del self.received_configurations['DEFAULT'] + self.test_configs_factory.add_new_config( + chain, self.received_configurations) - mock_ack.return_value = None + self.test_system_alerter._initialise_rabbitmq() + method = pika.spec.Basic.Deliver( + routing_key=SYSTEM_TRANSFORMED_DATA_ROUTING_KEY) + body = json.dumps(self.transformed_data_example_result) - try: - self.test_system_alerter.rabbitmq.connect() - blocking_channel = self.test_system_alerter.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=self.bad_output_routing_key) - del self.data_received_error_data['error']['meta_data'] - body = json.dumps(self.data_received_error_data) - properties = pika.spec.BasicProperties() - self.test_system_alerter._process_data(blocking_channel, method, - properties, body) - mock_create_state_for_system.assert_not_called() - mock_process_errors.assert_not_called() - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch( - "src.alerter.alerters.system.SystemAlerter._place_latest_data_on_queue") - @mock.patch.object(RabbitMQApi, "basic_ack") - def test_place_latest_data_on_queue_not_called_bad_routing_key( - self, mock_ack, mock_place_latest_data_on_queue) -> None: - mock_ack.return_value = None - try: - self.test_system_alerter.rabbitmq.connect() - blocking_channel = self.test_system_alerter.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=self.bad_output_routing_key) - body = json.dumps(self.data_received_initially_no_alert) - properties = pika.spec.BasicProperties() - self.test_system_alerter._process_data(blocking_channel, method, - properties, body) - mock_place_latest_data_on_queue.assert_not_called() - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch( - "src.alerter.alerters.system.SystemAlerter._place_latest_data_on_queue") - @mock.patch.object(RabbitMQApi, "basic_ack") - def test_process_error_data_not_processed_bad_routing_key( - self, mock_ack, mock_place_latest_data_on_queue) -> None: + self.assertRaises(exception_class, + self.test_system_alerter._process_transformed_data, + method, body) - mock_ack.return_value = None - try: - self.test_system_alerter.rabbitmq.connect() - blocking_channel = self.test_system_alerter.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=self.bad_output_routing_key) - body = json.dumps(self.data_received_error_data) - properties = pika.spec.BasicProperties() - self.test_system_alerter._process_data(blocking_channel, method, - properties, body) - mock_place_latest_data_on_queue.assert_not_called() - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch( - "src.alerter.alerters.system.SystemAlerter._place_latest_data_on_queue") - @mock.patch.object(RabbitMQApi, "basic_ack") - def test_place_latest_data_on_queue_not_called_bad_data_received( - self, mock_ack, mock_place_latest_data_on_queue) -> None: - mock_ack.return_value = None - try: - self.test_system_alerter.rabbitmq.connect() - blocking_channel = self.test_system_alerter.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=self.bad_output_routing_key) - del self.data_received_initially_no_alert['result']['data'] - body = json.dumps(self.data_received_initially_no_alert) - properties = pika.spec.BasicProperties() - self.test_system_alerter._process_data(blocking_channel, method, - properties, body) - mock_place_latest_data_on_queue.assert_not_called() - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch( - "src.alerter.alerters.system.SystemAlerter._place_latest_data_on_queue") - @mock.patch.object(RabbitMQApi, "basic_ack") - def test_process_error_data_not_processed_bad_data_received( - self, mock_ack, mock_place_latest_data_on_queue) -> None: - mock_ack.return_value = None - try: - self.test_system_alerter.rabbitmq.connect() - blocking_channel = self.test_system_alerter.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=self.bad_output_routing_key) - del self.data_received_error_data['error']['meta_data'] - body = json.dumps(self.data_received_error_data) - properties = pika.spec.BasicProperties() - self.test_system_alerter._process_data(blocking_channel, method, - properties, body) - mock_place_latest_data_on_queue.assert_not_called() - except Exception as e: - self.fail("Test failed: {}".format(e)) + mock_basic_ack.assert_called_once() diff --git a/alerter/test/alerter/factory/test_alerting_factory.py b/alerter/test/alerter/factory/test_alerting_factory.py index 18769ccd0..e320ea58d 100644 --- a/alerter/test/alerter/factory/test_alerting_factory.py +++ b/alerter/test/alerter/factory/test_alerting_factory.py @@ -6,6 +6,9 @@ from freezegun import freeze_time from parameterized import parameterized +from src.alerter.alert_code.node.chainlink_alert_code import \ + ChainlinkNodeAlertCode +from src.alerter.alerts.alert import Alert from src.alerter.alerts.node.chainlink import ( NoChangeInHeightAlert, BlockHeightUpdatedAlert, TotalErroredJobRunsIncreasedAboveThresholdAlert, @@ -13,8 +16,7 @@ MaxUnconfirmedBlocksIncreasedAboveThresholdAlert, MaxUnconfirmedBlocksDecreasedBelowThresholdAlert, ChangeInSourceNodeAlert, PrometheusSourceIsDownAlert, - PrometheusSourceBackUpAgainAlert, EthBalanceIncreasedAboveThresholdAlert, - EthBalanceDecreasedBelowThresholdAlert, InvalidUrlAlert, ValidUrlAlert, + PrometheusSourceBackUpAgainAlert, InvalidUrlAlert, ValidUrlAlert, NodeWentDownAtAlert, NodeBackUpAgainAlert, NodeStillDownAlert) from src.alerter.alerts.node.cosmos import ( NodeIsSyncingAlert, NodeIsNoLongerSyncingAlert @@ -45,6 +47,30 @@ """ +class IncreasedAboveThresholdTestAlert(Alert): + def __init__(self, origin_name: str, current_value: float, severity: str, + timestamp: float, threshold_severity: str, parent_id: str, + origin_id: str) -> None: + super().__init__( + ChainlinkNodeAlertCode.BalanceIncreasedAboveThresholdAlert, + "{} has INCREASED above {} threshold. Current value: {}.".format( + origin_name, threshold_severity, current_value), + severity, timestamp, parent_id, origin_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold) + + +class DecreasedBelowThresholdTestAlert(Alert): + def __init__(self, origin_name: str, current_value: float, severity: str, + timestamp: float, threshold_severity: str, parent_id: str, + origin_id: str) -> None: + super().__init__( + ChainlinkNodeAlertCode.BalanceDecreasedBelowThresholdAlert, + "{} has DECREASED below {} threshold. Current value: {}.".format( + origin_name, threshold_severity, current_value), + severity, timestamp, parent_id, origin_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold) + + class ChainlinkAlertingFactoryInstance(AlertingFactory): def __init__(self, component_logger: logging.Logger) -> None: super().__init__(component_logger) @@ -67,7 +93,7 @@ def create_alerting_state( TotalErroredJobRunsThreshold.value: False, GroupedChainlinkNodeAlertsMetricCode. MaxUnconfirmedBlocksThreshold.value: False, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value: + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value: False, GroupedChainlinkNodeAlertsMetricCode.NodeIsDown.value: False, GroupedChainlinkNodeAlertsMetricCode.PrometheusSourceIsDown: @@ -80,7 +106,7 @@ def create_alerting_state( MaxUnconfirmedBlocksThreshold.value: False, GroupedChainlinkNodeAlertsMetricCode. TotalErroredJobRunsThreshold.value: False, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value: + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value: False, GroupedChainlinkNodeAlertsMetricCode.NodeIsDown.value: False, } @@ -91,8 +117,8 @@ def create_alerting_state( current_head_thresholds = parse_alert_time_thresholds( ['warning_threshold', 'critical_threshold', 'critical_repeat'], cl_node_alerts_config.head_tracker_current_head) - eth_balance_thresholds = parse_alert_time_thresholds( - ['critical_repeat'], cl_node_alerts_config.eth_balance_amount + balance_thresholds = parse_alert_time_thresholds( + ['critical_repeat'], cl_node_alerts_config.balance_amount ) node_is_down_thresholds = parse_alert_time_thresholds( ['warning_threshold', 'critical_threshold', @@ -138,8 +164,8 @@ def create_alerting_state( GroupedChainlinkNodeAlertsMetricCode.NoChangeInHeight.value: TimedTaskLimiter(timedelta( seconds=current_head_thresholds['critical_repeat'])), - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value: - TimedTaskLimiter(timedelta(seconds=eth_balance_thresholds[ + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value: + TimedTaskLimiter(timedelta(seconds=balance_thresholds[ 'critical_repeat'])), GroupedChainlinkNodeAlertsMetricCode.NodeIsDown.value: TimedTaskLimiter(timedelta(seconds=node_is_down_thresholds[ @@ -402,8 +428,8 @@ def setUp(self) -> None: 'warning_time_window': '3', 'critical_time_window': '7', } - self.eth_balance_amount = { - 'name': 'eth_balance_amount', + self.balance_amount = { + 'name': 'balance_amount', 'parent_id': self.test_parent_id, 'enabled': 'true', 'critical_threshold': '5', @@ -433,8 +459,8 @@ def setUp(self) -> None: tx_manager_gas_bump_exceeds_limit_total={}, unconfirmed_transactions={}, run_status_update_total=self.run_status_update_total, - eth_balance_amount=self.eth_balance_amount, - eth_balance_amount_increase={}, node_is_down=self.node_is_down, + balance_amount=self.balance_amount, + balance_amount_increase={}, node_is_down=self.node_is_down, ) self.test_factory_instance = ChainlinkAlertingFactoryInstance( self.dummy_logger) @@ -1882,308 +1908,6 @@ def condition_function(*args): return False self.assertEqual([], data_for_alerting) - def test_classify_thresholded_reverse_does_nothing_warning_critical_disabled( - self) -> None: - """ - In this test we will check that no alert is raised whenever both warning - and critical alerts are disabled. We will perform this test for both - when current <= critical and current <= warning. For an alert to be - raised when current > critical or current > warning it must be that one - of the severities is enabled. - """ - self.test_alerts_config.eth_balance_amount[ - 'warning_enabled'] = 'False' - self.test_alerts_config.eth_balance_amount[ - 'critical_enabled'] = 'False' - - data_for_alerting = [] - current = float(self.test_alerts_config.eth_balance_amount[ - 'critical_threshold']) - 1 - self.test_factory_instance.classify_thresholded_alert_reverse( - current, self.test_alerts_config.eth_balance_amount, - EthBalanceIncreasedAboveThresholdAlert, - EthBalanceDecreasedBelowThresholdAlert, data_for_alerting, - self.test_parent_id, self.test_node_id, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value, - self.test_node_name, datetime.now().timestamp() - ) - - self.assertEqual([], data_for_alerting) - - @parameterized.expand([ - ('WARNING', 'warning_threshold'), - ('CRITICAL', 'critical_threshold'), - ]) - @freeze_time("2012-01-01") - def test_classify_thresholded_reverse_raises_alert_if_below_threshold( - self, severity, threshold_var) -> None: - """ - In this test we will check that a warning/critical below threshold alert - is raised if the current value goes below the warning/critical - threshold. - """ - data_for_alerting = [] - - current = float( - self.test_alerts_config.eth_balance_amount[threshold_var]) - 1 - self.test_factory_instance.classify_thresholded_alert_reverse( - current, self.test_alerts_config.eth_balance_amount, - EthBalanceIncreasedAboveThresholdAlert, - EthBalanceDecreasedBelowThresholdAlert, data_for_alerting, - self.test_parent_id, self.test_node_id, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value, - self.test_node_name, datetime.now().timestamp() - ) - expected_alert = EthBalanceDecreasedBelowThresholdAlert( - self.test_node_name, current, severity, datetime.now().timestamp(), - severity, self.test_parent_id, self.test_node_id) - self.assertEqual(1, len(data_for_alerting)) - self.assertEqual(expected_alert.alert_data, data_for_alerting[0]) - - @freeze_time("2012-01-01") - def test_classify_thresholded_reverse_no_warning_if_warning_already_sent( - self) -> None: - """ - In this test we will check that no warning alert is raised if a warning - alert has already been sent - """ - data_for_alerting = [] - - # Send first warning alert - current = float( - self.test_alerts_config.eth_balance_amount['warning_threshold']) - 1 - self.test_factory_instance.classify_thresholded_alert_reverse( - current, self.test_alerts_config.eth_balance_amount, - EthBalanceIncreasedAboveThresholdAlert, - EthBalanceDecreasedBelowThresholdAlert, data_for_alerting, - self.test_parent_id, self.test_node_id, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value, - self.test_node_name, datetime.now().timestamp() - ) - self.assertEqual(1, len(data_for_alerting)) - data_for_alerting.clear() - - # Classify again to check if a warning alert is raised - self.test_factory_instance.classify_thresholded_alert_reverse( - current, self.test_alerts_config.eth_balance_amount, - EthBalanceIncreasedAboveThresholdAlert, - EthBalanceDecreasedBelowThresholdAlert, data_for_alerting, - self.test_parent_id, self.test_node_id, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value, - self.test_node_name, datetime.now().timestamp() + 1 - ) - self.assertEqual([], data_for_alerting) - - @freeze_time("2012-01-01") - def test_classify_thresholded_reverse_raises_critical_if_repeat_elapsed( - self) -> None: - """ - In this test we will check that a critical below threshold alert is - re-raised if the critical repeat window elapses. We will also check that - if the critical window does not elapse, a critical alert is not - re-raised. - """ - data_for_alerting = [] - - # First critical below threshold alert - current = float(self.test_alerts_config.eth_balance_amount[ - 'critical_threshold']) - 1 - self.test_factory_instance.classify_thresholded_alert_reverse( - current, self.test_alerts_config.eth_balance_amount, - EthBalanceIncreasedAboveThresholdAlert, - EthBalanceDecreasedBelowThresholdAlert, data_for_alerting, - self.test_parent_id, self.test_node_id, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value, - self.test_node_name, datetime.now().timestamp() - ) - self.assertEqual(1, len(data_for_alerting)) - data_for_alerting.clear() - - # Classify with not elapsed repeat to confirm that no critical alert is - # raised. - pad = float(self.test_alerts_config.eth_balance_amount[ - 'critical_repeat']) - 1 - alert_timestamp = datetime.now().timestamp() + pad - self.test_factory_instance.classify_thresholded_alert_reverse( - current, self.test_alerts_config.eth_balance_amount, - EthBalanceIncreasedAboveThresholdAlert, - EthBalanceDecreasedBelowThresholdAlert, data_for_alerting, - self.test_parent_id, self.test_node_id, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value, - self.test_node_name, alert_timestamp - ) - self.assertEqual([], data_for_alerting) - - # Let repeat time to elapse and check that a critical alert is - # re-raised - pad = float(self.test_alerts_config.eth_balance_amount[ - 'critical_repeat']) - alert_timestamp = datetime.now().timestamp() + pad - self.test_factory_instance.classify_thresholded_alert_reverse( - current, self.test_alerts_config.eth_balance_amount, - EthBalanceIncreasedAboveThresholdAlert, - EthBalanceDecreasedBelowThresholdAlert, data_for_alerting, - self.test_parent_id, self.test_node_id, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value, - self.test_node_name, alert_timestamp - ) - expected_alert = EthBalanceDecreasedBelowThresholdAlert( - self.test_node_name, current, "CRITICAL", alert_timestamp, - "CRITICAL", self.test_parent_id, self.test_node_id) - self.assertEqual(1, len(data_for_alerting)) - self.assertEqual(expected_alert.alert_data, data_for_alerting[0]) - - @freeze_time("2012-01-01") - def test_classify_threshold_reverse_only_1_critical_if_below_and_no_repeat( - self) -> None: - """ - In this test we will check that if critical_repeat is disabled, a - decreased below critical alert is not re-raised. - """ - self.test_alerts_config.eth_balance_amount[ - 'critical_repeat_enabled'] = "False" - data_for_alerting = [] - - # First critical below threshold alert - current = float(self.test_alerts_config.eth_balance_amount[ - 'critical_threshold']) - 1 - self.test_factory_instance.classify_thresholded_alert_reverse( - current, self.test_alerts_config.eth_balance_amount, - EthBalanceIncreasedAboveThresholdAlert, - EthBalanceDecreasedBelowThresholdAlert, data_for_alerting, - self.test_parent_id, self.test_node_id, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value, - self.test_node_name, datetime.now().timestamp() - ) - self.assertEqual(1, len(data_for_alerting)) - data_for_alerting.clear() - - # Let repeat time to elapse and check that a critical alert is not - # re-raised - pad = float(self.test_alerts_config.eth_balance_amount[ - 'critical_repeat']) - alert_timestamp = datetime.now().timestamp() + pad - self.test_factory_instance.classify_thresholded_alert_reverse( - current, self.test_alerts_config.eth_balance_amount, - EthBalanceIncreasedAboveThresholdAlert, - EthBalanceDecreasedBelowThresholdAlert, data_for_alerting, - self.test_parent_id, self.test_node_id, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value, - self.test_node_name, alert_timestamp - ) - self.assertEqual([], data_for_alerting) - - @parameterized.expand([ - ('critical_threshold', 'CRITICAL',), - ('warning_threshold', 'WARNING',) - ]) - @freeze_time("2012-01-01") - def test_classify_thresh_reverse_info_alert_if_above_thresh_and_alert_sent( - self, threshold_var, threshold_severity) -> None: - """ - In this test we will check that once the current value is greater than a - threshold, an increased above threshold info alert is sent. We will - perform this test for both warning and critical. - """ - data_for_alerting = [] - - # First below threshold alert - current = float(self.test_alerts_config.eth_balance_amount[ - threshold_var]) - 1 - self.test_factory_instance.classify_thresholded_alert_reverse( - current, self.test_alerts_config.eth_balance_amount, - EthBalanceIncreasedAboveThresholdAlert, - EthBalanceDecreasedBelowThresholdAlert, data_for_alerting, - self.test_parent_id, self.test_node_id, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value, - self.test_node_name, datetime.now().timestamp() - ) - self.assertEqual(1, len(data_for_alerting)) - data_for_alerting.clear() - - # Check that an above threshold INFO alert is raised. Current is set to - # warning + 1 to not trigger a warning alert as it is expected that - # critical <= warning. - current = float(self.test_alerts_config.eth_balance_amount[ - 'warning_threshold']) + 1 - alert_timestamp = datetime.now().timestamp() - self.test_factory_instance.classify_thresholded_alert_reverse( - current, self.test_alerts_config.eth_balance_amount, - EthBalanceIncreasedAboveThresholdAlert, - EthBalanceDecreasedBelowThresholdAlert, data_for_alerting, - self.test_parent_id, self.test_node_id, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value, - self.test_node_name, alert_timestamp - ) - expected_alert = EthBalanceIncreasedAboveThresholdAlert( - self.test_node_name, current, 'INFO', alert_timestamp, - threshold_severity, self.test_parent_id, self.test_node_id) - self.assertEqual(1, len(data_for_alerting)) - self.assertEqual(expected_alert.alert_data, data_for_alerting[0]) - - @freeze_time("2012-01-01") - def test_classify_thresh_reverse_warn_alert_if_above_critical_below_warn( - self) -> None: - """ - In this test we will check that whenever - warning >= current >= critical >= previous, a warning alert is raised to - inform that the current value is smaller than the warning value. Note - we will perform this test for the case when we first alert warning, then - critical and not immediately critical, as the warning alerting would be - obvious. - """ - data_for_alerting = [] - - # Send warning decrease below threshold alert - current = float(self.test_alerts_config.eth_balance_amount[ - 'warning_threshold']) - 1 - self.test_factory_instance.classify_thresholded_alert_reverse( - current, self.test_alerts_config.eth_balance_amount, - EthBalanceIncreasedAboveThresholdAlert, - EthBalanceDecreasedBelowThresholdAlert, data_for_alerting, - self.test_parent_id, self.test_node_id, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value, - self.test_node_name, datetime.now().timestamp() - ) - self.assertEqual(1, len(data_for_alerting)) - - # Send critical decrease below threshold alert - current = float(self.test_alerts_config.eth_balance_amount[ - 'critical_threshold']) - 1 - self.test_factory_instance.classify_thresholded_alert_reverse( - current, self.test_alerts_config.eth_balance_amount, - EthBalanceIncreasedAboveThresholdAlert, - EthBalanceDecreasedBelowThresholdAlert, data_for_alerting, - self.test_parent_id, self.test_node_id, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value, - self.test_node_name, datetime.now().timestamp() - ) - self.assertEqual(2, len(data_for_alerting)) - data_for_alerting.clear() - - # Check that 2 alerts are raised, above critical and below warning - current = float(self.test_alerts_config.eth_balance_amount[ - 'critical_threshold']) + 1 - alert_timestamp = datetime.now().timestamp() + 10 - self.test_factory_instance.classify_thresholded_alert_reverse( - current, self.test_alerts_config.eth_balance_amount, - EthBalanceIncreasedAboveThresholdAlert, - EthBalanceDecreasedBelowThresholdAlert, data_for_alerting, - self.test_parent_id, self.test_node_id, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value, - self.test_node_name, alert_timestamp - ) - - expected_alert_1 = EthBalanceIncreasedAboveThresholdAlert( - self.test_node_name, current, 'INFO', alert_timestamp, - 'CRITICAL', self.test_parent_id, self.test_node_id) - expected_alert_2 = EthBalanceDecreasedBelowThresholdAlert( - self.test_node_name, current, 'WARNING', alert_timestamp, - 'WARNING', self.test_parent_id, self.test_node_id) - self.assertEqual(2, len(data_for_alerting)) - self.assertEqual(expected_alert_1.alert_data, data_for_alerting[0]) - self.assertEqual(expected_alert_2.alert_data, data_for_alerting[1]) - def test_classify_thresholded_does_nothing_warning_critical_disabled( self) -> None: """ @@ -3064,3 +2788,305 @@ def condition_function_false(*args): return not condition_function_true( ) self.assertEqual([], data_for_alerting) + + def test_classify_thresholded_reverse_does_nothing_warning_critical_disabled( + self) -> None: + """ + In this test we will check that no alert is raised whenever both warning + and critical alerts are disabled. We will perform this test for both + when current <= critical and current <= warning. For an alert to be + raised when current > critical or current > warning it must be that one + of the severities is enabled. + """ + self.test_alerts_config.balance_amount[ + 'warning_enabled'] = 'False' + self.test_alerts_config.balance_amount[ + 'critical_enabled'] = 'False' + + data_for_alerting = [] + current = float(self.test_alerts_config.balance_amount[ + 'critical_threshold']) - 1 + self.test_factory_instance.classify_thresholded_alert_reverse( + current, self.test_alerts_config.balance_amount, + IncreasedAboveThresholdTestAlert, + DecreasedBelowThresholdTestAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold, + self.test_node_name, datetime.now().timestamp() + ) + + self.assertEqual([], data_for_alerting) + + @parameterized.expand([ + ('WARNING', 'warning_threshold'), + ('CRITICAL', 'critical_threshold'), + ]) + @freeze_time("2012-01-01") + def test_classify_thresholded_reverse_raises_alert_if_below_threshold( + self, severity, threshold_var) -> None: + """ + In this test we will check that a warning/critical below threshold alert + is raised if the current value goes below the warning/critical + threshold. + """ + data_for_alerting = [] + + current = float( + self.test_alerts_config.balance_amount[threshold_var]) - 1 + self.test_factory_instance.classify_thresholded_alert_reverse( + current, self.test_alerts_config.balance_amount, + IncreasedAboveThresholdTestAlert, + DecreasedBelowThresholdTestAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold, + self.test_node_name, datetime.now().timestamp() + ) + expected_alert = DecreasedBelowThresholdTestAlert( + self.test_node_name, current, severity, datetime.now().timestamp(), + severity, self.test_parent_id, self.test_node_id) + self.assertEqual(1, len(data_for_alerting)) + self.assertEqual(expected_alert.alert_data, data_for_alerting[0]) + + @freeze_time("2012-01-01") + def test_classify_thresholded_reverse_no_warning_if_warning_already_sent( + self) -> None: + """ + In this test we will check that no warning alert is raised if a warning + alert has already been sent + """ + data_for_alerting = [] + + # Send first warning alert + current = float( + self.test_alerts_config.balance_amount['warning_threshold']) - 1 + self.test_factory_instance.classify_thresholded_alert_reverse( + current, self.test_alerts_config.balance_amount, + IncreasedAboveThresholdTestAlert, + DecreasedBelowThresholdTestAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold, + self.test_node_name, datetime.now().timestamp() + ) + self.assertEqual(1, len(data_for_alerting)) + data_for_alerting.clear() + + # Classify again to check if a warning alert is raised + self.test_factory_instance.classify_thresholded_alert_reverse( + current, self.test_alerts_config.balance_amount, + IncreasedAboveThresholdTestAlert, + DecreasedBelowThresholdTestAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold, + self.test_node_name, datetime.now().timestamp() + 1 + ) + self.assertEqual([], data_for_alerting) + + @freeze_time("2012-01-01") + def test_classify_thresholded_reverse_raises_critical_if_repeat_elapsed( + self) -> None: + """ + In this test we will check that a critical below threshold alert is + re-raised if the critical repeat window elapses. We will also check that + if the critical window does not elapse, a critical alert is not + re-raised. + """ + data_for_alerting = [] + + # First critical below threshold alert + current = float(self.test_alerts_config.balance_amount[ + 'critical_threshold']) - 1 + self.test_factory_instance.classify_thresholded_alert_reverse( + current, self.test_alerts_config.balance_amount, + IncreasedAboveThresholdTestAlert, + DecreasedBelowThresholdTestAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, datetime.now().timestamp() + ) + self.assertEqual(1, len(data_for_alerting)) + data_for_alerting.clear() + + # Classify with not elapsed repeat to confirm that no critical alert is + # raised. + pad = float(self.test_alerts_config.balance_amount[ + 'critical_repeat']) - 1 + alert_timestamp = datetime.now().timestamp() + pad + self.test_factory_instance.classify_thresholded_alert_reverse( + current, self.test_alerts_config.balance_amount, + IncreasedAboveThresholdTestAlert, + DecreasedBelowThresholdTestAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, alert_timestamp + ) + self.assertEqual([], data_for_alerting) + + # Let repeat time to elapse and check that a critical alert is + # re-raised + pad = float(self.test_alerts_config.balance_amount[ + 'critical_repeat']) + alert_timestamp = datetime.now().timestamp() + pad + self.test_factory_instance.classify_thresholded_alert_reverse( + current, self.test_alerts_config.balance_amount, + IncreasedAboveThresholdTestAlert, + DecreasedBelowThresholdTestAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, alert_timestamp + ) + expected_alert = DecreasedBelowThresholdTestAlert( + self.test_node_name, current, "CRITICAL", alert_timestamp, + "CRITICAL", self.test_parent_id, self.test_node_id) + self.assertEqual(1, len(data_for_alerting)) + self.assertEqual(expected_alert.alert_data, data_for_alerting[0]) + + @freeze_time("2012-01-01") + def test_classify_threshold_reverse_only_1_critical_if_below_and_no_repeat( + self) -> None: + """ + In this test we will check that if critical_repeat is disabled, a + decreased below critical alert is not re-raised. + """ + self.test_alerts_config.balance_amount[ + 'critical_repeat_enabled'] = "False" + data_for_alerting = [] + + # First critical below threshold alert + current = float(self.test_alerts_config.balance_amount[ + 'critical_threshold']) - 1 + self.test_factory_instance.classify_thresholded_alert_reverse( + current, self.test_alerts_config.balance_amount, + IncreasedAboveThresholdTestAlert, + DecreasedBelowThresholdTestAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, datetime.now().timestamp() + ) + self.assertEqual(1, len(data_for_alerting)) + data_for_alerting.clear() + + # Let repeat time to elapse and check that a critical alert is not + # re-raised + pad = float(self.test_alerts_config.balance_amount[ + 'critical_repeat']) + alert_timestamp = datetime.now().timestamp() + pad + self.test_factory_instance.classify_thresholded_alert_reverse( + current, self.test_alerts_config.balance_amount, + IncreasedAboveThresholdTestAlert, + DecreasedBelowThresholdTestAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, alert_timestamp + ) + self.assertEqual([], data_for_alerting) + + @parameterized.expand([ + ('critical_threshold', 'CRITICAL',), + ('warning_threshold', 'WARNING',) + ]) + @freeze_time("2012-01-01") + def test_classify_thresh_reverse_info_alert_if_above_thresh_and_alert_sent( + self, threshold_var, threshold_severity) -> None: + """ + In this test we will check that once the current value is greater than a + threshold, an increased above threshold info alert is sent. We will + perform this test for both warning and critical. + """ + data_for_alerting = [] + + # First below threshold alert + current = float(self.test_alerts_config.balance_amount[ + threshold_var]) - 1 + self.test_factory_instance.classify_thresholded_alert_reverse( + current, self.test_alerts_config.balance_amount, + IncreasedAboveThresholdTestAlert, + DecreasedBelowThresholdTestAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, datetime.now().timestamp() + ) + self.assertEqual(1, len(data_for_alerting)) + data_for_alerting.clear() + + # Check that an above threshold INFO alert is raised. Current is set to + # warning + 1 to not trigger a warning alert as it is expected that + # critical <= warning. + current = float(self.test_alerts_config.balance_amount[ + 'warning_threshold']) + 1 + alert_timestamp = datetime.now().timestamp() + self.test_factory_instance.classify_thresholded_alert_reverse( + current, self.test_alerts_config.balance_amount, + IncreasedAboveThresholdTestAlert, + DecreasedBelowThresholdTestAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, alert_timestamp + ) + expected_alert = IncreasedAboveThresholdTestAlert( + self.test_node_name, current, 'INFO', alert_timestamp, + threshold_severity, self.test_parent_id, self.test_node_id) + self.assertEqual(1, len(data_for_alerting)) + self.assertEqual(expected_alert.alert_data, data_for_alerting[0]) + + @freeze_time("2012-01-01") + def test_classify_thresh_reverse_warn_alert_if_above_critical_below_warn( + self) -> None: + """ + In this test we will check that whenever + warning >= current >= critical >= previous, a warning alert is raised to + inform that the current value is smaller than the warning value. Note + we will perform this test for the case when we first alert warning, then + critical and not immediately critical, as the warning alerting would be + obvious. + """ + data_for_alerting = [] + + # Send warning decrease below threshold alert + current = float(self.test_alerts_config.balance_amount[ + 'warning_threshold']) - 1 + self.test_factory_instance.classify_thresholded_alert_reverse( + current, self.test_alerts_config.balance_amount, + IncreasedAboveThresholdTestAlert, + DecreasedBelowThresholdTestAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, datetime.now().timestamp() + ) + self.assertEqual(1, len(data_for_alerting)) + + # Send critical decrease below threshold alert + current = float(self.test_alerts_config.balance_amount[ + 'critical_threshold']) - 1 + self.test_factory_instance.classify_thresholded_alert_reverse( + current, self.test_alerts_config.balance_amount, + IncreasedAboveThresholdTestAlert, + DecreasedBelowThresholdTestAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, datetime.now().timestamp() + ) + self.assertEqual(2, len(data_for_alerting)) + data_for_alerting.clear() + + # Check that 2 alerts are raised, above critical and below warning + current = float(self.test_alerts_config.balance_amount[ + 'critical_threshold']) + 1 + alert_timestamp = datetime.now().timestamp() + 10 + self.test_factory_instance.classify_thresholded_alert_reverse( + current, self.test_alerts_config.balance_amount, + IncreasedAboveThresholdTestAlert, + DecreasedBelowThresholdTestAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, alert_timestamp + ) + + expected_alert_1 = IncreasedAboveThresholdTestAlert( + self.test_node_name, current, 'INFO', alert_timestamp, 'CRITICAL', + self.test_parent_id, self.test_node_id) + expected_alert_2 = DecreasedBelowThresholdTestAlert( + self.test_node_name, current, 'WARNING', alert_timestamp, 'WARNING', + self.test_parent_id, self.test_node_id) + self.assertEqual(2, len(data_for_alerting)) + self.assertEqual(expected_alert_1.alert_data, data_for_alerting[0]) + self.assertEqual(expected_alert_2.alert_data, data_for_alerting[1]) diff --git a/alerter/test/alerter/factory/test_chainlink_node_alerting_factory.py b/alerter/test/alerter/factory/test_chainlink_node_alerting_factory.py index dc671da05..9a1d6b24f 100644 --- a/alerter/test/alerter/factory/test_chainlink_node_alerting_factory.py +++ b/alerter/test/alerter/factory/test_chainlink_node_alerting_factory.py @@ -1,8 +1,13 @@ import copy import logging import unittest -from datetime import timedelta +from datetime import timedelta, datetime +from freezegun import freeze_time +from parameterized import parameterized + +from src.alerter.alerts.node.chainlink import ( + BalanceIncreasedAboveThresholdAlert, BalanceDecreasedBelowThresholdAlert) from src.alerter.factory.chainlink_node_alerting_factory import \ ChainlinkNodeAlertingFactory from src.alerter.grouped_alerts_metric_code.node.chainlink_node_metric_code \ @@ -19,6 +24,8 @@ def setUp(self) -> None: self.dummy_logger = logging.getLogger('dummy') self.test_parent_id = 'test_parent_id' self.test_node_id = 'test_node_id' + self.test_node_name = 'test_node_name' + self.test_symbol = 'TEST' self.test_dummy_parent_id1 = 'dummy_parent_id1' self.test_dummy_node_id1 = 'dummy_node_id1' self.test_dummy_node_id2 = 'dummy_node_id2' @@ -27,7 +34,7 @@ def setUp(self) -> None: # Construct the configs metrics_without_time_window = [ 'head_tracker_current_head', 'head_tracker_heads_received_total', - 'eth_balance_amount', 'node_is_down' + 'balance_amount', 'node_is_down' ] metrics_with_time_window = [ 'max_unconfirmed_blocks', @@ -36,7 +43,7 @@ def setUp(self) -> None: severity_metrics = [ 'process_start_time_seconds', 'tx_manager_gas_bump_exceeds_limit_total', - 'eth_balance_amount_increase' + 'balance_amount_increase' ] filtered = {} @@ -45,11 +52,11 @@ def setUp(self) -> None: 'name': metric, 'parent_id': self.test_parent_id, 'enabled': 'true', - 'critical_threshold': '7', + 'critical_threshold': '5', 'critical_repeat': '5', 'critical_enabled': 'true', 'critical_repeat_enabled': 'true', - 'warning_threshold': '3', + 'warning_threshold': '10', 'warning_enabled': 'true' } for metric in metrics_with_time_window: @@ -74,7 +81,7 @@ def setUp(self) -> None: 'severity': 'WARNING' } - self.cl_node_alerts_config = ChainlinkNodeAlertsConfig( + self.test_alerts_config = ChainlinkNodeAlertsConfig( parent_id=self.test_parent_id, head_tracker_current_head=filtered[ 'head_tracker_current_head'], @@ -88,20 +95,22 @@ def setUp(self) -> None: unconfirmed_transactions=filtered[ 'unconfirmed_transactions'], run_status_update_total=filtered['run_status_update_total'], - eth_balance_amount=filtered['eth_balance_amount'], - eth_balance_amount_increase=filtered[ - 'eth_balance_amount_increase'], + balance_amount=filtered['balance_amount'], + balance_amount_increase=filtered[ + 'balance_amount_increase'], node_is_down=filtered['node_is_down'] ) # Test object - self.chainlink_node_alerting_factory = ChainlinkNodeAlertingFactory( + self.test_factory_instance = ChainlinkNodeAlertingFactory( self.dummy_logger) + self.test_factory_instance.create_alerting_state( + self.test_parent_id, self.test_node_id, self.test_alerts_config) def tearDown(self) -> None: self.dummy_logger = None - self.cl_node_alerts_config = None - self.chainlink_node_alerting_factory = None + self.test_alerts_config = None + self.test_factory_instance = None def test_create_alerting_state_creates_the_correct_state(self) -> None: """ @@ -111,7 +120,7 @@ def test_create_alerting_state_creates_the_correct_state(self) -> None: # We will also set a dummy state to confirm that the correct chain and # node are updated - self.chainlink_node_alerting_factory._alerting_state = { + self.test_factory_instance._alerting_state = { self.test_parent_id: { self.test_dummy_node_id1: self.test_dummy_state }, @@ -130,7 +139,7 @@ def test_create_alerting_state_creates_the_correct_state(self) -> None: .value: False, GroupedChainlinkNodeAlertsMetricCode.TotalErroredJobRunsThreshold .value: False, - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value: + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value: False, GroupedChainlinkNodeAlertsMetricCode.NodeIsDown.value: False, } @@ -148,28 +157,28 @@ def test_create_alerting_state_creates_the_correct_state(self) -> None: current_head_thresholds = parse_alert_time_thresholds( ['warning_threshold', 'critical_threshold', 'critical_repeat'], - self.cl_node_alerts_config.head_tracker_current_head) + self.test_alerts_config.head_tracker_current_head) total_headers_thresholds = parse_alert_time_thresholds( ['warning_threshold', 'critical_threshold', 'critical_repeat'], - self.cl_node_alerts_config.head_tracker_heads_received_total) + self.test_alerts_config.head_tracker_heads_received_total) unconfirmed_blocks_thresholds = parse_alert_time_thresholds( ['warning_time_window', 'critical_time_window', 'critical_repeat'], - self.cl_node_alerts_config.max_unconfirmed_blocks + self.test_alerts_config.max_unconfirmed_blocks ) unconfirmed_txs_thresholds = parse_alert_time_thresholds( ['warning_time_window', 'critical_time_window', 'critical_repeat'], - self.cl_node_alerts_config.unconfirmed_transactions + self.test_alerts_config.unconfirmed_transactions ) error_jobs_thresholds = parse_alert_time_thresholds( ['warning_time_window', 'critical_time_window', 'critical_repeat'], - self.cl_node_alerts_config.run_status_update_total + self.test_alerts_config.run_status_update_total ) - eth_balance_thresholds = parse_alert_time_thresholds( - ['critical_repeat'], self.cl_node_alerts_config.eth_balance_amount + balance_thresholds = parse_alert_time_thresholds( + ['critical_repeat'], self.test_alerts_config.balance_amount ) node_is_down_thresholds = parse_alert_time_thresholds( ['warning_threshold', 'critical_threshold', 'critical_repeat'], - self.cl_node_alerts_config.node_is_down + self.test_alerts_config.node_is_down ) warning_window_timer = { @@ -239,8 +248,8 @@ def test_create_alerting_state_creates_the_correct_state(self) -> None: TimedTaskLimiter( timedelta(seconds=error_jobs_thresholds[ 'critical_repeat'])), - GroupedChainlinkNodeAlertsMetricCode.EthBalanceThreshold.value: - TimedTaskLimiter(timedelta(seconds=eth_balance_thresholds[ + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value: + TimedTaskLimiter(timedelta(seconds=balance_thresholds[ 'critical_repeat'])), GroupedChainlinkNodeAlertsMetricCode.NodeIsDown.value: TimedTaskLimiter(timedelta(seconds=node_is_down_thresholds[ @@ -280,11 +289,11 @@ def test_create_alerting_state_creates_the_correct_state(self) -> None: } } - self.chainlink_node_alerting_factory.create_alerting_state( - self.test_parent_id, self.test_node_id, self.cl_node_alerts_config) + self.test_factory_instance.create_alerting_state( + self.test_parent_id, self.test_node_id, self.test_alerts_config) self.assertDictEqual( - expected_state, self.chainlink_node_alerting_factory.alerting_state) + expected_state, self.test_factory_instance.alerting_state) def test_create_alerting_state_does_not_modify_state_if_already_created( self) -> None: @@ -292,7 +301,7 @@ def test_create_alerting_state_does_not_modify_state_if_already_created( In this test we will check that if a node's state is already created it cannot be overwritten. """ - self.chainlink_node_alerting_factory._alerting_state = { + self.test_factory_instance._alerting_state = { self.test_parent_id: { self.test_node_id: self.test_dummy_state, self.test_dummy_node_id1: self.test_dummy_state, @@ -302,13 +311,13 @@ def test_create_alerting_state_does_not_modify_state_if_already_created( } } expected_state = copy.deepcopy( - self.chainlink_node_alerting_factory.alerting_state) + self.test_factory_instance.alerting_state) - self.chainlink_node_alerting_factory.create_alerting_state( - self.test_parent_id, self.test_node_id, self.cl_node_alerts_config) + self.test_factory_instance.create_alerting_state( + self.test_parent_id, self.test_node_id, self.test_alerts_config) self.assertEqual(expected_state, - self.chainlink_node_alerting_factory.alerting_state) + self.test_factory_instance.alerting_state) def test_remove_chain_alerting_state_removes_chain_alerting_state_correctly( self) -> None: @@ -316,7 +325,7 @@ def test_remove_chain_alerting_state_removes_chain_alerting_state_correctly( In this test we will check that the remove function removes the alerting state of the given chain """ - self.chainlink_node_alerting_factory._alerting_state = { + self.test_factory_instance._alerting_state = { self.test_parent_id: { self.test_node_id: self.test_dummy_state, self.test_dummy_node_id1: self.test_dummy_state, @@ -326,13 +335,13 @@ def test_remove_chain_alerting_state_removes_chain_alerting_state_correctly( } } expected_state = copy.deepcopy( - self.chainlink_node_alerting_factory.alerting_state) + self.test_factory_instance.alerting_state) del expected_state[self.test_parent_id] - self.chainlink_node_alerting_factory.remove_chain_alerting_state( + self.test_factory_instance.remove_chain_alerting_state( self.test_parent_id) self.assertEqual(expected_state, - self.chainlink_node_alerting_factory.alerting_state) + self.test_factory_instance.alerting_state) def test_remove_chain_alerting_state_does_nothing_if_chain_does_not_exist( self) -> None: @@ -340,7 +349,7 @@ def test_remove_chain_alerting_state_does_nothing_if_chain_does_not_exist( In this test we will check that if no alerting state has been created for the chain, then the state is unmodified. """ - self.chainlink_node_alerting_factory._alerting_state = { + self.test_factory_instance._alerting_state = { self.test_parent_id: { self.test_node_id: self.test_dummy_state, self.test_dummy_node_id1: self.test_dummy_state, @@ -350,9 +359,313 @@ def test_remove_chain_alerting_state_does_nothing_if_chain_does_not_exist( } } expected_state = copy.deepcopy( - self.chainlink_node_alerting_factory.alerting_state) + self.test_factory_instance.alerting_state) - self.chainlink_node_alerting_factory.remove_chain_alerting_state( + self.test_factory_instance.remove_chain_alerting_state( 'bad_chain_id') self.assertEqual(expected_state, - self.chainlink_node_alerting_factory.alerting_state) + self.test_factory_instance.alerting_state) + + def test_classify_thresholded_reverse_does_nothing_warning_critical_disabled( + self) -> None: + """ + In this test we will check that no alert is raised whenever both warning + and critical alerts are disabled. We will perform this test for both + when current <= critical and current <= warning. For an alert to be + raised when current > critical or current > warning it must be that one + of the severities is enabled. + """ + self.test_alerts_config.balance_amount[ + 'warning_enabled'] = 'False' + self.test_alerts_config.balance_amount[ + 'critical_enabled'] = 'False' + + data_for_alerting = [] + current = float(self.test_alerts_config.balance_amount[ + 'critical_threshold']) - 1 + self.test_factory_instance.classify_thresholded_alert_reverse_chainlink_node( + current, self.test_alerts_config.balance_amount, 'TEST', + BalanceIncreasedAboveThresholdAlert, + BalanceDecreasedBelowThresholdAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, datetime.now().timestamp() + ) + + self.assertEqual([], data_for_alerting) + + @parameterized.expand([ + ('WARNING', 'warning_threshold'), + ('CRITICAL', 'critical_threshold'), + ]) + @freeze_time("2012-01-01") + def test_classify_thresholded_reverse_raises_alert_if_below_threshold( + self, severity, threshold_var) -> None: + """ + In this test we will check that a warning/critical below threshold alert + is raised if the current value goes below the warning/critical + threshold. + """ + data_for_alerting = [] + + current = float( + self.test_alerts_config.balance_amount[threshold_var]) - 1 + self.test_factory_instance.classify_thresholded_alert_reverse_chainlink_node( + current, self.test_alerts_config.balance_amount, 'TEST', + BalanceIncreasedAboveThresholdAlert, + BalanceDecreasedBelowThresholdAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, datetime.now().timestamp() + ) + expected_alert = BalanceDecreasedBelowThresholdAlert( + self.test_node_name, current, self.test_symbol, severity, + datetime.now().timestamp(), severity, self.test_parent_id, + self.test_node_id) + self.assertEqual(1, len(data_for_alerting)) + self.assertEqual(expected_alert.alert_data, data_for_alerting[0]) + + @freeze_time("2012-01-01") + def test_classify_thresholded_reverse_no_warning_if_warning_already_sent( + self) -> None: + """ + In this test we will check that no warning alert is raised if a warning + alert has already been sent + """ + data_for_alerting = [] + + # Send first warning alert + current = float( + self.test_alerts_config.balance_amount['warning_threshold']) - 1 + self.test_factory_instance.classify_thresholded_alert_reverse_chainlink_node( + current, self.test_alerts_config.balance_amount, 'TEST', + BalanceIncreasedAboveThresholdAlert, + BalanceDecreasedBelowThresholdAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, datetime.now().timestamp() + ) + self.assertEqual(1, len(data_for_alerting)) + data_for_alerting.clear() + + # Classify again to check if a warning alert is raised + self.test_factory_instance.classify_thresholded_alert_reverse_chainlink_node( + current, self.test_alerts_config.balance_amount, 'TEST', + BalanceIncreasedAboveThresholdAlert, + BalanceDecreasedBelowThresholdAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, datetime.now().timestamp() + 1 + ) + self.assertEqual([], data_for_alerting) + + @freeze_time("2012-01-01") + def test_classify_thresholded_reverse_raises_critical_if_repeat_elapsed( + self) -> None: + """ + In this test we will check that a critical below threshold alert is + re-raised if the critical repeat window elapses. We will also check that + if the critical window does not elapse, a critical alert is not + re-raised. + """ + data_for_alerting = [] + + # First critical below threshold alert + current = float(self.test_alerts_config.balance_amount[ + 'critical_threshold']) - 1 + self.test_factory_instance.classify_thresholded_alert_reverse_chainlink_node( + current, self.test_alerts_config.balance_amount, 'TEST', + BalanceIncreasedAboveThresholdAlert, + BalanceDecreasedBelowThresholdAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, datetime.now().timestamp() + ) + self.assertEqual(1, len(data_for_alerting)) + data_for_alerting.clear() + + # Classify with not elapsed repeat to confirm that no critical alert is + # raised. + pad = float(self.test_alerts_config.balance_amount[ + 'critical_repeat']) - 1 + alert_timestamp = datetime.now().timestamp() + pad + self.test_factory_instance.classify_thresholded_alert_reverse_chainlink_node( + current, self.test_alerts_config.balance_amount, 'TEST', + BalanceIncreasedAboveThresholdAlert, + BalanceDecreasedBelowThresholdAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, alert_timestamp + ) + self.assertEqual([], data_for_alerting) + + # Let repeat time to elapse and check that a critical alert is + # re-raised + pad = float(self.test_alerts_config.balance_amount[ + 'critical_repeat']) + alert_timestamp = datetime.now().timestamp() + pad + self.test_factory_instance.classify_thresholded_alert_reverse_chainlink_node( + current, self.test_alerts_config.balance_amount, 'TEST', + BalanceIncreasedAboveThresholdAlert, + BalanceDecreasedBelowThresholdAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, alert_timestamp + ) + expected_alert = BalanceDecreasedBelowThresholdAlert( + self.test_node_name, current, self.test_symbol, "CRITICAL", + alert_timestamp, "CRITICAL", self.test_parent_id, self.test_node_id) + self.assertEqual(1, len(data_for_alerting)) + self.assertEqual(expected_alert.alert_data, data_for_alerting[0]) + + @freeze_time("2012-01-01") + def test_classify_threshold_reverse_only_1_critical_if_below_and_no_repeat( + self) -> None: + """ + In this test we will check that if critical_repeat is disabled, a + decreased below critical alert is not re-raised. + """ + self.test_alerts_config.balance_amount[ + 'critical_repeat_enabled'] = "False" + data_for_alerting = [] + + # First critical below threshold alert + current = float(self.test_alerts_config.balance_amount[ + 'critical_threshold']) - 1 + self.test_factory_instance.classify_thresholded_alert_reverse_chainlink_node( + current, self.test_alerts_config.balance_amount, 'TEST', + BalanceIncreasedAboveThresholdAlert, + BalanceDecreasedBelowThresholdAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, datetime.now().timestamp() + ) + self.assertEqual(1, len(data_for_alerting)) + data_for_alerting.clear() + + # Let repeat time to elapse and check that a critical alert is not + # re-raised + pad = float(self.test_alerts_config.balance_amount[ + 'critical_repeat']) + alert_timestamp = datetime.now().timestamp() + pad + self.test_factory_instance.classify_thresholded_alert_reverse_chainlink_node( + current, self.test_alerts_config.balance_amount, 'TEST', + BalanceIncreasedAboveThresholdAlert, + BalanceDecreasedBelowThresholdAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, alert_timestamp + ) + self.assertEqual([], data_for_alerting) + + @parameterized.expand([ + ('critical_threshold', 'CRITICAL',), + ('warning_threshold', 'WARNING',) + ]) + @freeze_time("2012-01-01") + def test_classify_thresh_reverse_info_alert_if_above_thresh_and_alert_sent( + self, threshold_var, threshold_severity) -> None: + """ + In this test we will check that once the current value is greater than a + threshold, an increased above threshold info alert is sent. We will + perform this test for both warning and critical. + """ + data_for_alerting = [] + + # First below threshold alert + current = float(self.test_alerts_config.balance_amount[ + threshold_var]) - 1 + self.test_factory_instance.classify_thresholded_alert_reverse_chainlink_node( + current, self.test_alerts_config.balance_amount, 'TEST', + BalanceIncreasedAboveThresholdAlert, + BalanceDecreasedBelowThresholdAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, datetime.now().timestamp() + ) + self.assertEqual(1, len(data_for_alerting)) + data_for_alerting.clear() + + # Check that an above threshold INFO alert is raised. Current is set to + # warning + 1 to not trigger a warning alert as it is expected that + # critical <= warning. + current = float(self.test_alerts_config.balance_amount[ + 'warning_threshold']) + 1 + alert_timestamp = datetime.now().timestamp() + self.test_factory_instance.classify_thresholded_alert_reverse_chainlink_node( + current, self.test_alerts_config.balance_amount, 'TEST', + BalanceIncreasedAboveThresholdAlert, + BalanceDecreasedBelowThresholdAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, alert_timestamp + ) + expected_alert = BalanceIncreasedAboveThresholdAlert( + self.test_node_name, current, self.test_symbol, 'INFO', + alert_timestamp, threshold_severity, self.test_parent_id, + self.test_node_id) + self.assertEqual(1, len(data_for_alerting)) + self.assertEqual(expected_alert.alert_data, data_for_alerting[0]) + + @freeze_time("2012-01-01") + def test_classify_thresh_reverse_warn_alert_if_above_critical_below_warn( + self) -> None: + """ + In this test we will check that whenever + warning >= current >= critical >= previous, a warning alert is raised to + inform that the current value is smaller than the warning value. Note + we will perform this test for the case when we first alert warning, then + critical and not immediately critical, as the warning alerting would be + obvious. + """ + data_for_alerting = [] + + # Send warning decrease below threshold alert + current = float(self.test_alerts_config.balance_amount[ + 'warning_threshold']) - 1 + self.test_factory_instance.classify_thresholded_alert_reverse_chainlink_node( + current, self.test_alerts_config.balance_amount, 'TEST', + BalanceIncreasedAboveThresholdAlert, + BalanceDecreasedBelowThresholdAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, datetime.now().timestamp() + ) + self.assertEqual(1, len(data_for_alerting)) + + # Send critical decrease below threshold alert + current = float(self.test_alerts_config.balance_amount[ + 'critical_threshold']) - 1 + self.test_factory_instance.classify_thresholded_alert_reverse_chainlink_node( + current, self.test_alerts_config.balance_amount, 'TEST', + BalanceIncreasedAboveThresholdAlert, + BalanceDecreasedBelowThresholdAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, datetime.now().timestamp() + ) + self.assertEqual(2, len(data_for_alerting)) + data_for_alerting.clear() + + # Check that 2 alerts are raised, above critical and below warning + current = float(self.test_alerts_config.balance_amount[ + 'critical_threshold']) + 1 + alert_timestamp = datetime.now().timestamp() + 10 + self.test_factory_instance.classify_thresholded_alert_reverse_chainlink_node( + current, self.test_alerts_config.balance_amount, 'TEST', + BalanceIncreasedAboveThresholdAlert, + BalanceDecreasedBelowThresholdAlert, data_for_alerting, + self.test_parent_id, self.test_node_id, + GroupedChainlinkNodeAlertsMetricCode.BalanceThreshold.value, + self.test_node_name, alert_timestamp + ) + + expected_alert_1 = BalanceIncreasedAboveThresholdAlert( + self.test_node_name, current, self.test_symbol, 'INFO', + alert_timestamp, 'CRITICAL', self.test_parent_id, self.test_node_id) + expected_alert_2 = BalanceDecreasedBelowThresholdAlert( + self.test_node_name, current, self.test_symbol, 'WARNING', + alert_timestamp, 'WARNING', self.test_parent_id, self.test_node_id) + self.assertEqual(2, len(data_for_alerting)) + self.assertEqual(expected_alert_1.alert_data, data_for_alerting[0]) + self.assertEqual(expected_alert_2.alert_data, data_for_alerting[1]) diff --git a/alerter/test/alerter/factory/test_evm_node_alerting_factory.py b/alerter/test/alerter/factory/test_evm_node_alerting_factory.py index 5c336ea86..b4edffa75 100644 --- a/alerter/test/alerter/factory/test_evm_node_alerting_factory.py +++ b/alerter/test/alerter/factory/test_evm_node_alerting_factory.py @@ -78,14 +78,6 @@ def test_create_alerting_state_creates_the_correct_state(self) -> None: self.test_dummy_node_id2: self.test_dummy_state } } - self.evm_node_alerting_factory._nodes_configs = { - self.test_parent_id: { - self.test_dummy_node_id1: None - }, - self.test_dummy_parent_id1: { - self.test_dummy_node_id2: None - } - } warning_critical_sent_dict = { MetricCode.NoChangeInBlockHeight.value: False, MetricCode.BlockHeightDifference.value: False, @@ -208,14 +200,6 @@ def test_remove_chain_alerting_state_removes_chain_alerting_state_correctly( self.test_dummy_node_id2: self.test_dummy_state } } - self.evm_node_alerting_factory._nodes_configs = { - self.test_parent_id: { - self.test_node_id: None, - }, - self.test_dummy_parent_id1: { - self.test_dummy_node_id2: None - } - } expected_state = copy.deepcopy( self.evm_node_alerting_factory.alerting_state) del expected_state[self.test_parent_id] diff --git a/alerter/test/alerter/factory/test_system_alerting_factory.py b/alerter/test/alerter/factory/test_system_alerting_factory.py new file mode 100644 index 000000000..349ecf124 --- /dev/null +++ b/alerter/test/alerter/factory/test_system_alerting_factory.py @@ -0,0 +1,268 @@ +import copy +import logging +import unittest +from datetime import timedelta + +from src.alerter.factory.system_alerting_factory import SystemAlertingFactory +from src.alerter.grouped_alerts_metric_code.system \ + import GroupedSystemAlertsMetricCode as MetricCode +from src.configs.alerts.system import SystemAlertsConfig +from src.utils.configs import parse_alert_time_thresholds +from src.utils.timing import (TimedTaskTracker, TimedTaskLimiter) + + +class TestSystemAlertingFactory(unittest.TestCase): + def setUp(self) -> None: + # Some dummy data and objects + self.dummy_logger = logging.getLogger('dummy') + self.test_parent_id = 'test_parent_id' + self.test_system_id = 'test_system_id' + self.test_dummy_parent_id1 = 'dummy_parent_id1' + self.test_dummy_system_id1 = 'dummy_system_id1' + self.test_dummy_system_id2 = 'dummy_system_id2' + self.test_dummy_state = 'dummy_state' + + # Construct the configs + all_metrics = [ + 'open_file_descriptors', + 'system_cpu_usage', + 'system_storage_usage', + 'system_ram_usage', + 'system_is_down' + ] + + filtered = {} + for metric in all_metrics: + filtered[metric] = { + 'name': metric, + 'parent_id': self.test_parent_id, + 'enabled': 'true', + 'critical_threshold': '95', + 'critical_repeat': '300', + 'critical_enabled': 'true', + 'critical_repeat_enabled': 'true', + 'warning_threshold': '85', + 'warning_enabled': 'true' + } + + self.system_alerts_config = SystemAlertsConfig( + parent_id=self.test_parent_id, + open_file_descriptors=filtered['open_file_descriptors'], + system_cpu_usage=filtered['system_cpu_usage'], + system_storage_usage=filtered['system_storage_usage'], + system_ram_usage=filtered['system_ram_usage'], + system_is_down=filtered['system_is_down'] + ) + + # Test object + self.system_alerting_factory = SystemAlertingFactory(self.dummy_logger) + + def tearDown(self) -> None: + self.dummy_logger = None + self.system_alerts_config = None + self.system_alerting_factory = None + + def test_create_alerting_state_creates_the_correct_state(self) -> None: + """ + In this test we will check that all alerting tools are created correctly + for the given parent_id and system_id. + """ + + # We will also set a dummy state to confirm that the correct chain and + # system are updated + self.system_alerting_factory._alerting_state = { + self.test_parent_id: { + self.test_dummy_system_id1: self.test_dummy_state + }, + self.test_dummy_parent_id1: { + self.test_dummy_system_id2: self.test_dummy_state + } + } + warning_critical_sent_dict = { + MetricCode.OpenFileDescriptorsThreshold.value: False, + MetricCode.SystemCPUUsageThreshold.value: False, + MetricCode.SystemStorageUsageThreshold.value: False, + MetricCode.SystemRAMUsageThreshold.value: False, + MetricCode.SystemIsDown.value: False + } + + warning_sent = copy.deepcopy(warning_critical_sent_dict) + critical_sent = copy.deepcopy(warning_critical_sent_dict) + error_sent = { + MetricCode.InvalidUrl.value: False, + MetricCode.MetricNotFound.value: False, + } + + open_file_descriptors_thresholds = parse_alert_time_thresholds( + ['warning_threshold', 'critical_threshold', 'critical_repeat'], + self.system_alerts_config.open_file_descriptors) + system_cpu_usage_thresholds = parse_alert_time_thresholds( + ['warning_threshold', 'critical_threshold', 'critical_repeat'], + self.system_alerts_config.system_cpu_usage) + system_ram_usage_thresholds = parse_alert_time_thresholds( + ['warning_threshold', 'critical_threshold', 'critical_repeat'], + self.system_alerts_config.system_ram_usage + ) + system_storage_usage_thresholds = parse_alert_time_thresholds( + ['warning_threshold', 'critical_threshold', 'critical_repeat'], + self.system_alerts_config.system_storage_usage + ) + system_is_down_thresholds = parse_alert_time_thresholds( + ['warning_threshold', 'critical_threshold', 'critical_repeat'], + self.system_alerts_config.system_is_down + ) + + warning_window_timer = { + MetricCode.OpenFileDescriptorsThreshold.value: + TimedTaskTracker(timedelta( + seconds=open_file_descriptors_thresholds[ + 'warning_threshold'])), + MetricCode.SystemCPUUsageThreshold.value: + TimedTaskTracker(timedelta( + seconds=system_cpu_usage_thresholds['warning_threshold'] + )), + MetricCode.SystemRAMUsageThreshold.value: + TimedTaskTracker(timedelta( + seconds=system_ram_usage_thresholds[ + 'warning_threshold'])), + MetricCode.SystemStorageUsageThreshold.value: + TimedTaskTracker(timedelta( + seconds=system_storage_usage_thresholds[ + 'warning_threshold'])), + MetricCode.SystemIsDown.value: TimedTaskTracker(timedelta( + seconds=system_is_down_thresholds['warning_threshold'])) + } + critical_window_timer = { + MetricCode.OpenFileDescriptorsThreshold.value: + TimedTaskTracker(timedelta( + seconds=open_file_descriptors_thresholds[ + 'critical_threshold'])), + MetricCode.SystemCPUUsageThreshold.value: + TimedTaskTracker(timedelta( + seconds=system_cpu_usage_thresholds[ + 'critical_threshold'])), + MetricCode.SystemRAMUsageThreshold.value: + TimedTaskTracker(timedelta( + seconds=system_ram_usage_thresholds[ + 'critical_threshold'])), + MetricCode.SystemStorageUsageThreshold.value: + TimedTaskTracker(timedelta( + seconds=system_storage_usage_thresholds[ + 'critical_threshold'])), + MetricCode.SystemIsDown.value: TimedTaskTracker(timedelta( + seconds=system_is_down_thresholds['critical_threshold'])) + } + critical_repeat_timer = { + MetricCode.OpenFileDescriptorsThreshold.value: + TimedTaskLimiter(timedelta( + seconds=open_file_descriptors_thresholds[ + 'critical_repeat'])), + MetricCode.SystemCPUUsageThreshold.value: + TimedTaskLimiter(timedelta( + seconds=system_cpu_usage_thresholds['critical_repeat']) + ), + MetricCode.SystemRAMUsageThreshold.value: + TimedTaskLimiter(timedelta( + seconds=system_ram_usage_thresholds['critical_repeat']) + ), + MetricCode.SystemStorageUsageThreshold.value: + TimedTaskLimiter(timedelta( + seconds=system_storage_usage_thresholds[ + 'critical_repeat'])), + MetricCode.SystemIsDown.value: TimedTaskLimiter(timedelta( + seconds=system_is_down_thresholds['critical_repeat'])) + } + + expected_state = { + self.test_parent_id: { + self.test_system_id: { + 'warning_sent': warning_sent, + 'critical_sent': critical_sent, + 'error_sent': error_sent, + 'warning_window_timer': warning_window_timer, + 'critical_window_timer': critical_window_timer, + 'critical_repeat_timer': critical_repeat_timer + }, + self.test_dummy_system_id1: self.test_dummy_state + }, + self.test_dummy_parent_id1: { + self.test_dummy_system_id2: self.test_dummy_state + } + } + + self.system_alerting_factory.create_alerting_state( + self.test_parent_id, self.test_system_id, self.system_alerts_config) + + self.assertDictEqual( + expected_state, self.system_alerting_factory.alerting_state) + + def test_create_alerting_state_does_not_modify_state_if_already_created( + self) -> None: + """ + In this test we will check that a system's state cannot be overwritten + if it has already been created. + """ + self.system_alerting_factory._alerting_state = { + self.test_parent_id: { + self.test_system_id: self.test_dummy_state, + self.test_dummy_system_id1: self.test_dummy_state, + }, + self.test_dummy_parent_id1: { + self.test_dummy_system_id2: self.test_dummy_state + } + } + expected_state = copy.deepcopy( + self.system_alerting_factory.alerting_state) + + self.system_alerting_factory.create_alerting_state( + self.test_parent_id, self.test_system_id, self.system_alerts_config) + + self.assertEqual(expected_state, + self.system_alerting_factory.alerting_state) + + def test_remove_chain_alerting_state_removes_chain_alerting_state_correctly( + self) -> None: + """ + In this test we will check that the remove function removes the alerting + state of the given chain + """ + self.system_alerting_factory._alerting_state = { + self.test_parent_id: { + self.test_system_id: self.test_dummy_state, + self.test_dummy_system_id1: self.test_dummy_state, + }, + self.test_dummy_parent_id1: { + self.test_dummy_system_id2: self.test_dummy_state + } + } + expected_state = copy.deepcopy( + self.system_alerting_factory.alerting_state) + del expected_state[self.test_parent_id] + + self.system_alerting_factory.remove_chain_alerting_state( + self.test_parent_id) + self.assertEqual(expected_state, + self.system_alerting_factory.alerting_state) + + def test_remove_chain_alerting_state_does_nothing_if_chain_does_not_exist( + self) -> None: + """ + In this test we will check that if no alerting state has been created + for the chain, then the state is unmodified. + """ + self.system_alerting_factory._alerting_state = { + self.test_parent_id: { + self.test_system_id: self.test_dummy_state, + self.test_dummy_system_id1: self.test_dummy_state, + }, + self.test_dummy_parent_id1: { + self.test_dummy_system_id2: self.test_dummy_state + } + } + expected_state = copy.deepcopy( + self.system_alerting_factory.alerting_state) + + self.system_alerting_factory.remove_chain_alerting_state( + 'bad_chain_id') + self.assertEqual(expected_state, + self.system_alerting_factory.alerting_state) diff --git a/alerter/test/alerter/managers/test_chainlink.py b/alerter/test/alerter/managers/test_chainlink.py index 4e84d16fb..fd5801d3e 100644 --- a/alerter/test/alerter/managers/test_chainlink.py +++ b/alerter/test/alerter/managers/test_chainlink.py @@ -101,11 +101,11 @@ def setUp(self) -> None: "parent_id": self.parent_id_1, }, "8": { - "name": "eth_balance_amount", + "name": "balance_amount", "parent_id": self.parent_id_1, }, "9": { - "name": "eth_balance_amount_increase", + "name": "balance_amount_increase", "parent_id": self.parent_id_1, }, "10": { @@ -595,8 +595,8 @@ def test_process_configs_if_non_empty_configs_received( tx_manager_gas_bump_exceeds_limit_total=self.config_1['5'], unconfirmed_transactions=self.config_1['6'], run_status_update_total=self.config_1['7'], - eth_balance_amount=self.config_1['8'], - eth_balance_amount_increase=self.config_1['9'], + balance_amount=self.config_1['8'], + balance_amount_increase=self.config_1['9'], node_is_down=self.config_1['10'] ) } @@ -666,8 +666,8 @@ def test_process_configs_if_received_empty_configs( tx_manager_gas_bump_exceeds_limit_total=self.config_1['5'], unconfirmed_transactions=self.config_1['6'], run_status_update_total=self.config_1['7'], - eth_balance_amount=self.config_1['8'], - eth_balance_amount_increase=self.config_1['9'], + balance_amount=self.config_1['8'], + balance_amount_increase=self.config_1['9'], node_is_down=self.config_1['10'] ) } diff --git a/alerter/test/alerter/managers/test_system.py b/alerter/test/alerter/managers/test_system.py index 03e262e30..fa0162f85 100644 --- a/alerter/test/alerter/managers/test_system.py +++ b/alerter/test/alerter/managers/test_system.py @@ -1,8 +1,6 @@ -import copy import json import logging import multiprocessing -import time import unittest from datetime import timedelta, datetime from multiprocessing import Process @@ -12,1690 +10,681 @@ import pika import pika.exceptions from freezegun import freeze_time +from parameterized import parameterized +from src.abstract.publisher_subscriber import ( + QueuingPublisherSubscriberComponent) from src.alerter.alerter_starters import start_system_alerter from src.alerter.alerters.system import SystemAlerter from src.alerter.alerts.internal_alerts import ComponentResetAlert from src.alerter.managers.system import SystemAlertersManager from src.configs.alerts.system import SystemAlertsConfig +from src.configs.factory.alerts.system_alerts import SystemAlertsConfigsFactory from src.message_broker.rabbitmq import RabbitMQApi from src.utils import env -from src.utils.constants.names import SYSTEM_ALERTER_NAME_TEMPLATE +from src.utils.constants.names import SYSTEM_ALERTER_NAME from src.utils.constants.rabbitmq import ( - HEALTH_CHECK_EXCHANGE, CONFIG_EXCHANGE, - SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME, - SYS_ALERTERS_MAN_HEARTBEAT_QUEUE_NAME, PING_ROUTING_KEY, - ALERTS_CONFIGS_ROUTING_KEY_GEN, - HEARTBEAT_OUTPUT_MANAGER_ROUTING_KEY, SYSTEM_ALERT_ROUTING_KEY, - ALERT_EXCHANGE, TOPIC) + HEALTH_CHECK_EXCHANGE, CONFIG_EXCHANGE, ALERT_EXCHANGE, + SYS_ALERTERS_MAN_HEARTBEAT_QUEUE_NAME, + SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME, PING_ROUTING_KEY, + CL_ALERTS_CONFIGS_ROUTING_KEY, HEARTBEAT_OUTPUT_MANAGER_ROUTING_KEY, + SYSTEM_ALERT_ROUTING_KEY, ALERTS_CONFIGS_ROUTING_KEY_GEN) from src.utils.exceptions import PANICException, MessageWasNotDeliveredException -from test.test_utils.utils import infinite_fn +from test.test_utils.utils import ( + delete_exchange_if_exists, delete_queue_if_exists, disconnect_from_rabbit, + connect_to_rabbit, infinite_fn +) -# Tests adapted from Monitors managers class TestSystemAlertersManager(unittest.TestCase): def setUp(self) -> None: + # Some dummy objects self.dummy_logger = logging.getLogger('Dummy') self.dummy_logger.disabled = True - self.connection_check_time_interval = timedelta(seconds=0) - self.rabbitmq = RabbitMQApi( - self.dummy_logger, env.RABBIT_IP, - connection_check_time_interval=self.connection_check_time_interval) self.manager_name = 'test_system_alerters_manager' self.test_queue_name = 'Test Queue' self.test_data_str = 'test data' - self.parent_id_1 = 'test_parent_id_1' - self.parent_id_2 = 'test_parent_id_2' - self.parent_id_3 = 'test_parent_id_3' - - self.chain_1 = 'Substrate Polkadot' - self.chain_2 = 'general' - self.chain_3 = 'Cosmos' self.test_heartbeat = { - 'component_name': 'Test Component', + 'component_name': self.manager_name, 'is_alive': True, - 'timestamp': datetime(2012, 1, 1, 1).timestamp(), - } - self.dummy_process1 = Process(target=infinite_fn, args=()) - self.dummy_process1.daemon = True - self.dummy_process2 = Process(target=infinite_fn, args=()) - self.dummy_process2.daemon = True - self.dummy_process3 = Process(target=infinite_fn, args=()) - self.dummy_process3.daemon = True - self.config_process_dict_example = { - self.parent_id_1: { - "component_name": SYSTEM_ALERTER_NAME_TEMPLATE.format( - self.chain_1), - "process": self.dummy_process1, - "chain": self.chain_1 - }, - self.parent_id_2: { - "component_name": SYSTEM_ALERTER_NAME_TEMPLATE.format( - self.chain_2), - "process": self.dummy_process2, - "chain": self.chain_2 - } - } - self.expected_output = { - self.parent_id_1: { - "component_name": SYSTEM_ALERTER_NAME_TEMPLATE.format( - self.chain_1), - "process": self.dummy_process1, - "chain": self.chain_1 - }, - self.parent_id_2: { - "component_name": SYSTEM_ALERTER_NAME_TEMPLATE.format( - self.chain_2), - "process": self.dummy_process2, - "chain": self.chain_2 - } + 'timestamp': datetime(2012, 1, 1).timestamp(), } - """ - ############# Alerts config base configuration ###################### - """ - self.enabled_alert = "True" - self.critical_threshold_percentage = 95 - self.critical_threshold_seconds = 300 - self.critical_repeat_seconds = 300 - self.critical_enabled = "True" - self.warning_threshold_percentage = 85 - self.warning_threshold_seconds = 200 - self.warning_enabled = "True" - - # ALERTS CONFIG PARENT_1 - - self.base_config = { - "name": "base_percent_config", - "enabled": self.enabled_alert, - "parent_id": self.parent_id_1, - "critical_threshold": self.critical_threshold_percentage, - "critical_repeat": self.critical_repeat_seconds, - "critical_enabled": self.critical_enabled, - "warning_threshold": self.warning_threshold_percentage, - "warning_enabled": self.warning_enabled - } - - self.open_file_descriptors = copy.deepcopy(self.base_config) - self.open_file_descriptors['name'] = "open_file_descriptors" - - self.system_cpu_usage = copy.deepcopy(self.base_config) - self.system_cpu_usage['name'] = "system_cpu_usage" - - self.system_storage_usage = copy.deepcopy(self.base_config) - self.system_storage_usage['name'] = "system_storage_usage" - - self.system_ram_usage = copy.deepcopy(self.base_config) - self.system_ram_usage['name'] = "system_ram_usage" - - self.system_is_down = copy.deepcopy(self.base_config) - self.system_is_down['name'] = "system_is_down" - self.system_is_down['critical_threshold'] = \ - self.critical_threshold_seconds - self.system_is_down['warning_threshold'] = \ - self.warning_threshold_seconds - - self.sent_configs_example = { - 1: self.open_file_descriptors, - 2: self.system_cpu_usage, - 3: self.system_storage_usage, - 4: self.system_ram_usage, - 5: self.system_is_down - } - - self.sent_configs_example_with_default = { - "DEFAULT": {}, - "1": self.open_file_descriptors, - "2": self.system_cpu_usage, - "3": self.system_storage_usage, - "4": self.system_ram_usage, - "5": self.system_is_down - } - - self.sent_configs_example_with_missing_keys = { - "DEFAULT": {}, - "1": self.open_file_descriptors, - "2": self.system_cpu_usage, - "4": self.system_ram_usage, - "5": self.system_is_down - } - - # ALERTS CONFIG PARENT_2 - self.base_config_2 = { - "name": "base_percent_config", - "enabled": self.enabled_alert, - "parent_id": self.parent_id_2, - "critical_threshold": self.critical_threshold_percentage, - "critical_repeat": self.critical_repeat_seconds, - "critical_enabled": self.critical_enabled, - "warning_threshold": self.warning_threshold_percentage, - "warning_enabled": self.warning_enabled - } - - self.open_file_descriptors_2 = copy.deepcopy(self.base_config_2) - self.open_file_descriptors_2['name'] = "open_file_descriptors" - - self.system_cpu_usage_2 = copy.deepcopy(self.base_config_2) - self.system_cpu_usage_2['name'] = "system_cpu_usage" - - self.system_storage_usage_2 = copy.deepcopy(self.base_config_2) - self.system_storage_usage_2['name'] = "system_storage_usage" - - self.system_ram_usage_2 = copy.deepcopy(self.base_config_2) - self.system_ram_usage_2['name'] = "system_ram_usage" + self.dummy_process = Process(target=infinite_fn, args=()) + self.dummy_process.daemon = True + self.test_exception = PANICException('test_exception', 1) - self.system_is_down_2 = copy.deepcopy(self.base_config_2) - self.system_is_down_2['name'] = "system_is_down" - self.system_is_down_2['critical_threshold'] = \ - self.critical_threshold_seconds - self.system_is_down_2['warning_threshold'] = \ - self.warning_threshold_seconds + # RabbitMQ initialisation + self.connection_check_time_interval = timedelta(seconds=0) + self.rabbitmq = RabbitMQApi( + self.dummy_logger, env.RABBIT_IP, + connection_check_time_interval=self.connection_check_time_interval) - self.sent_configs_example_with_default_2 = { - "DEFAULT": {}, - "1": self.open_file_descriptors_2, - "2": self.system_cpu_usage_2, - "3": self.system_storage_usage_2, - "4": self.system_ram_usage_2, - "5": self.system_is_down_2 - } + # Test routing key and parent_id + self.chains_routing_key = 'chains.Substrate.Polkadot.alerts_config' + self.general_routing_key = ALERTS_CONFIGS_ROUTING_KEY_GEN + self.parent_id_1 = "chain_name_d21d780d-92cb-42de-a7c1-11b751654510" - self.sent_configs_example_with_default_2_missing_keys = { - "DEFAULT": {}, - "1": self.open_file_descriptors_2, - "2": self.system_cpu_usage_2, - "4": self.system_ram_usage_2, - "5": self.system_is_down_2 + self.config_1 = { + "1": { + "name": "open_file_descriptors", + "parent_id": self.parent_id_1, + }, + "2": { + "name": "system_cpu_usage", + "parent_id": self.parent_id_1, + }, + "3": { + "name": "system_storage_usage", + "parent_id": self.parent_id_1, + }, + "4": { + "name": "system_ram_usage", + "parent_id": self.parent_id_1, + }, + "5": { + "name": "system_is_down", + "parent_id": self.parent_id_1, + }, } - self.system_alerts_config = SystemAlertsConfig( - self.parent_id_1, - self.open_file_descriptors, - self.system_cpu_usage, - self.system_storage_usage, - self.system_ram_usage, - self.system_is_down - ) - - self.system_alerts_config_2 = SystemAlertsConfig( - self.parent_id_2, - self.open_file_descriptors_2, - self.system_cpu_usage_2, - self.system_storage_usage_2, - self.system_ram_usage_2, - self.system_is_down_2 - ) - self.test_manager = SystemAlertersManager( self.dummy_logger, self.manager_name, self.rabbitmq) - - self.empty_message = { - "DEFAULT": {} + self.alerter_process_dict_example = { + SYSTEM_ALERTER_NAME: self.dummy_process, + 'ANOTHER_TEST_ALERTER': self.dummy_process + } + self.alerts_config_factory_example = SystemAlertsConfigsFactory() + self.configs_processor_helper_example = { + SYSTEM_ALERTER_NAME: { + 'alerterClass': SystemAlerter, + 'factory': self.alerts_config_factory_example, + 'routing_key': SYSTEM_ALERT_ROUTING_KEY, + 'starter': start_system_alerter, + } } - self.chain_example_new = 'Substrate Polkadot' - self.chains_routing_key = 'chains.Substrate.Polkadot.alerts_config' - self.general_routing_key = ALERTS_CONFIGS_ROUTING_KEY_GEN - self.test_exception = PANICException('test_exception', 1) - self.systems_alerts_configs = {} def tearDown(self) -> None: # Delete any queues and exchanges which are common across many tests - try: - self.test_manager.rabbitmq.connect() - self.test_manager.rabbitmq.exchange_declare( - HEALTH_CHECK_EXCHANGE, TOPIC, False, True, False, False) - self.test_manager.rabbitmq.exchange_declare( - ALERT_EXCHANGE, TOPIC, False, True, False, False) - self.test_manager.rabbitmq.exchange_declare( - CONFIG_EXCHANGE, TOPIC, False, True, False, False) - # Declare queues incase they haven't been declared already - self.test_manager.rabbitmq.queue_declare( - queue=self.test_queue_name, durable=True, exclusive=False, - auto_delete=False, passive=False - ) - self.test_manager.rabbitmq.queue_declare( - queue=SYS_ALERTERS_MAN_HEARTBEAT_QUEUE_NAME, durable=True, - exclusive=False, auto_delete=False, passive=False - ) - self.test_manager.rabbitmq.queue_declare( - queue=SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME, durable=True, - exclusive=False, auto_delete=False, passive=False - ) - self.test_manager.rabbitmq.queue_purge(self.test_queue_name) - self.test_manager.rabbitmq.queue_purge( - SYS_ALERTERS_MAN_HEARTBEAT_QUEUE_NAME) - self.test_manager.rabbitmq.queue_purge( - SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME) - self.test_manager.rabbitmq.queue_delete(self.test_queue_name) - self.test_manager.rabbitmq.queue_delete( - SYS_ALERTERS_MAN_HEARTBEAT_QUEUE_NAME) - self.test_manager.rabbitmq.queue_delete( - SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME) - self.test_manager.rabbitmq.exchange_delete(HEALTH_CHECK_EXCHANGE) - self.test_manager.rabbitmq.exchange_delete(ALERT_EXCHANGE) - self.test_manager.rabbitmq.exchange_delete(CONFIG_EXCHANGE) - self.test_manager.rabbitmq.disconnect() - except Exception as e: - print("Test failed: {}".format(e)) + connect_to_rabbit(self.test_manager.rabbitmq) + + delete_exchange_if_exists(self.test_manager.rabbitmq, + HEALTH_CHECK_EXCHANGE) + delete_exchange_if_exists(self.test_manager.rabbitmq, ALERT_EXCHANGE) + delete_exchange_if_exists(self.test_manager.rabbitmq, CONFIG_EXCHANGE) + delete_queue_if_exists(self.test_manager.rabbitmq, self.test_queue_name) + delete_queue_if_exists(self.test_manager.rabbitmq, + SYS_ALERTERS_MAN_HEARTBEAT_QUEUE_NAME) + delete_queue_if_exists(self.test_manager.rabbitmq, + SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME) + + disconnect_from_rabbit(self.test_manager.rabbitmq) self.dummy_logger = None + self.dummy_process = None + self.connection_check_time_interval = None self.rabbitmq = None - self.test_manager = None self.test_exception = None - self.system_alerts_config = None - self.base_config = None - self.open_file_descriptors = None - self.system_cpu_usage = None - self.system_storage_usage = None - self.system_ram_usage = None - self.system_is_down = None - self.systems_alerts_configs = None - - self.dummy_process1 = None - self.dummy_process2 = None - self.dummy_process3 = None + self.alerts_config_factory_example = None + self.alerter_process_dict_example = None + self.test_manager = None + self.configs_processor_helper_example = None def test_str_returns_manager_name(self) -> None: - self.assertEqual(self.manager_name, self.test_manager.__str__()) + self.assertEqual(self.manager_name, str(self.test_manager)) def test_name_returns_manager_name(self) -> None: self.assertEqual(self.manager_name, self.test_manager.name) - def test_systems_configs_returns_systems_configs(self) -> None: - self.test_manager._systems_alerts_configs[self.parent_id_1] = \ - self.system_alerts_config - self.assertEqual(self.system_alerts_config, - self.test_manager.systems_alerts_configs[ - self.parent_id_1]) + def test_alerter_process_dict_returns_alerter_process_dict(self) -> None: + self.test_manager._alerter_process_dict = \ + self.alerter_process_dict_example + self.assertEqual(self.alerter_process_dict_example, + self.test_manager.alerter_process_dict) + + def test_alerts_config_factory_returns_alerts_config_factory(self) -> None: + self.test_manager._system_alerts_config_factory = \ + self.alerts_config_factory_example + self.assertEqual(self.alerts_config_factory_example, + self.test_manager.system_alerts_config_factory) + + def test_configs_processor_helper_return_correctly(self) -> None: + self.test_manager._configs_processor_helper = \ + self.configs_processor_helper_example + self.assertEqual(self.configs_processor_helper_example, + self.test_manager.configs_processor_helper) @mock.patch.object(RabbitMQApi, "start_consuming") def test_listen_for_data_calls_start_consuming( self, mock_start_consuming) -> None: mock_start_consuming.return_value = None self.test_manager._listen_for_data() - mock_start_consuming.assert_called_once() + self.assertEqual(1, mock_start_consuming.call_count) - @mock.patch.object(SystemAlertersManager, "_process_ping") + @mock.patch.object(RabbitMQApi, "basic_consume") def test_initialise_rabbitmq_initialises_everything_as_expected( - self, mock_process_ping) -> None: - mock_process_ping.return_value = None - try: - # To make sure that there is no connection/channel already - # established - self.assertIsNone(self.rabbitmq.connection) - self.assertIsNone(self.rabbitmq.channel) - - # To make sure that the exchanges and queues have not already been - # declared - self.test_manager.rabbitmq.connect() - - self.test_manager._initialise_rabbitmq() - - # Perform checks that the connection has been opened, marked as open - # and that the delivery confirmation variable is set. - self.assertTrue(self.test_manager.rabbitmq.is_connected) - self.assertTrue(self.test_manager.rabbitmq.connection.is_open) - self.assertTrue( - self.test_manager.rabbitmq.channel._delivery_confirmation) - - # Check whether the exchanges and queues have been creating by - # sending messages with the same routing keys as for the queues. We - # will also check if the size of the queues is 0 to confirm that - # basic_consume was called (it will store the msg in the component - # memory immediately). If one of the exchanges or queues is not - # created, then an exception will be thrown. Note when deleting the - # exchanges in the beginning we also released every binding, hence - # there is no other queue binded with the same routing key to any - # exchange at this point. - self.test_manager.rabbitmq.basic_publish_confirm( - exchange=HEALTH_CHECK_EXCHANGE, - routing_key=PING_ROUTING_KEY, body=self.test_data_str, - is_body_dict=False, - properties=pika.BasicProperties(delivery_mode=2), - mandatory=True) - self.test_manager.rabbitmq.basic_publish_confirm( - exchange=CONFIG_EXCHANGE, - routing_key=self.chains_routing_key, - body=self.test_data_str, is_body_dict=False, - properties=pika.BasicProperties(delivery_mode=2), - mandatory=True) - self.test_manager.rabbitmq.basic_publish_confirm( - exchange=CONFIG_EXCHANGE, - routing_key=ALERTS_CONFIGS_ROUTING_KEY_GEN, - body=self.test_data_str, is_body_dict=False, - properties=pika.BasicProperties(delivery_mode=2), - mandatory=True) - self.test_manager.rabbitmq.basic_publish_confirm( - exchange=ALERT_EXCHANGE, routing_key=SYSTEM_ALERT_ROUTING_KEY, - body=self.test_data_str, is_body_dict=False, - properties=pika.BasicProperties(delivery_mode=2), - mandatory=False - ) - - # Re-declare queue to get the number of messages - res = self.test_manager.rabbitmq.queue_declare( - SYS_ALERTERS_MAN_HEARTBEAT_QUEUE_NAME, False, True, False, - False) - self.assertEqual(0, res.method.message_count) - res = self.test_manager.rabbitmq.queue_declare( - SYS_ALERTERS_MANAGER_CONFIGS_QUEUE_NAME, False, True, False, - False) - self.assertEqual(0, res.method.message_count) - except Exception as e: - self.fail("Test failed: {}".format(e)) + self, mock_basic_consume) -> None: + mock_basic_consume.return_value = None + + # To make sure that there is no connection/channel already established + self.assertIsNone(self.rabbitmq.connection) + self.assertIsNone(self.rabbitmq.channel) + + # To make sure that the exchanges and queues have not already been + # declared + self.rabbitmq.connect() + self.test_manager.rabbitmq.queue_delete( + SYS_ALERTERS_MAN_HEARTBEAT_QUEUE_NAME) + self.test_manager.rabbitmq.queue_delete( + SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME) + self.test_manager.rabbitmq.exchange_delete(HEALTH_CHECK_EXCHANGE) + self.test_manager.rabbitmq.exchange_delete(CONFIG_EXCHANGE) + self.test_manager.rabbitmq.exchange_delete(ALERT_EXCHANGE) + self.rabbitmq.disconnect() + + self.test_manager._initialise_rabbitmq() + + # Perform checks that the connection has been opened, marked as open + # and that the delivery confirmation variable is set. + self.assertTrue(self.test_manager.rabbitmq.is_connected) + self.assertTrue(self.test_manager.rabbitmq.connection.is_open) + self.assertTrue( + self.test_manager.rabbitmq.channel._delivery_confirmation) + + # Check whether the producing exchanges have been created by using + # passive=True. If this check fails an exception is raised + # automatically. + self.test_manager.rabbitmq.exchange_declare(ALERT_EXCHANGE, + passive=True) + + # Check whether the consuming exchanges and queues have been creating by + # sending messages with the same routing keys as for the bindings. + self.test_manager.rabbitmq.basic_publish_confirm( + exchange=HEALTH_CHECK_EXCHANGE, routing_key=PING_ROUTING_KEY, + body='test_str', is_body_dict=False, + properties=pika.BasicProperties(delivery_mode=2), mandatory=True) + self.test_manager.rabbitmq.basic_publish_confirm( + exchange=CONFIG_EXCHANGE, routing_key=self.chains_routing_key, + body='another_test_str', is_body_dict=False, + properties=pika.BasicProperties(delivery_mode=2), mandatory=True) + self.test_manager.rabbitmq.basic_publish_confirm( + exchange=CONFIG_EXCHANGE, routing_key=self.general_routing_key, + body='another_test_str', is_body_dict=False, + properties=pika.BasicProperties(delivery_mode=2), mandatory=True) + + # Re-declare queue to get the number of messages, and check that the + # message received is the message sent + res = self.test_manager.rabbitmq.queue_declare( + SYS_ALERTERS_MAN_HEARTBEAT_QUEUE_NAME, False, True, False, + False) + self.assertEqual(1, res.method.message_count) + _, _, body = self.test_manager.rabbitmq.basic_get( + SYS_ALERTERS_MAN_HEARTBEAT_QUEUE_NAME) + self.assertEqual('test_str', body.decode()) + + res = self.test_manager.rabbitmq.queue_declare( + SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME, False, True, False, + False) + self.assertEqual(2, res.method.message_count) + _, _, body = self.test_manager.rabbitmq.basic_get( + SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME) + self.assertEqual('another_test_str', body.decode()) + + expected_calls = [ + call(SYS_ALERTERS_MAN_HEARTBEAT_QUEUE_NAME, + self.test_manager._process_ping, True, False, None), + call(SYS_ALERTERS_MAN_CONFIGS_QUEUE_NAME, + self.test_manager._process_configs, False, False, None) + ] + mock_basic_consume.assert_has_calls(expected_calls, True) def test_send_heartbeat_sends_a_heartbeat_correctly(self) -> None: # This test creates a queue which receives messages with the same - # routing key as the ones sent by send_heartbeat, and checks that the + # routing key as the ones set by send_heartbeat, and checks that the # heartbeat is received - try: - self.test_manager._initialise_rabbitmq() - - # Delete the queue before to avoid messages in the queue on error. - self.test_manager.rabbitmq.queue_delete(self.test_queue_name) - - res = self.test_manager.rabbitmq.queue_declare( - queue=self.test_queue_name, durable=True, exclusive=False, - auto_delete=False, passive=False - ) - self.assertEqual(0, res.method.message_count) - self.test_manager.rabbitmq.queue_bind( - queue=self.test_queue_name, exchange=HEALTH_CHECK_EXCHANGE, - routing_key=HEARTBEAT_OUTPUT_MANAGER_ROUTING_KEY) - self.test_manager._send_heartbeat(self.test_heartbeat) - - # By re-declaring the queue again we can get the number of messages - # in the queue. - res = self.test_manager.rabbitmq.queue_declare( - queue=self.test_queue_name, durable=True, exclusive=False, - auto_delete=False, passive=True - ) - self.assertEqual(1, res.method.message_count) + self.test_manager._initialise_rabbitmq() - # Check that the message received is actually the HB - _, _, body = self.test_manager.rabbitmq.basic_get( - self.test_queue_name) - self.assertEqual(self.test_heartbeat, json.loads(body)) - except Exception as e: - self.fail("Test failed: {}".format(e)) + # Delete the queue before to avoid messages in the queue on error. + self.test_manager.rabbitmq.queue_delete(self.test_queue_name) + res = self.test_manager.rabbitmq.queue_declare( + queue=self.test_queue_name, durable=True, exclusive=False, + auto_delete=False, passive=False + ) + self.assertEqual(0, res.method.message_count) + self.test_manager.rabbitmq.queue_bind( + queue=self.test_queue_name, exchange=HEALTH_CHECK_EXCHANGE, + routing_key=HEARTBEAT_OUTPUT_MANAGER_ROUTING_KEY) + + self.test_manager._send_heartbeat(self.test_heartbeat) + + # By re-declaring the queue again we can get the number of messages + # in the queue. + res = self.test_manager.rabbitmq.queue_declare( + queue=self.test_queue_name, durable=True, exclusive=False, + auto_delete=False, passive=True + ) + self.assertEqual(1, res.method.message_count) + + # Check that the message received is actually the HB + _, _, body = self.test_manager.rabbitmq.basic_get( + self.test_queue_name) + self.assertEqual(self.test_heartbeat, json.loads(body)) + + @parameterized.expand([ + ([True, True], [],), + ([True, False], ['ANOTHER_TEST_ALERTER'],), + ([False, True], [SYSTEM_ALERTER_NAME],), + ([False, False], [SYSTEM_ALERTER_NAME, 'ANOTHER_TEST_ALERTER'],), + ]) + @freeze_time("2012-01-01") + @mock.patch.object(multiprocessing.Process, "join") + @mock.patch.object(multiprocessing.Process, "is_alive") @mock.patch.object(SystemAlertersManager, - "_push_latest_data_to_queue_and_send") - @mock.patch.object(multiprocessing.Process, "start") - @mock.patch.object(multiprocessing, 'Process') - def test_create_and_start_alerter_process_stores_the_correct_process_info( - self, mock_init, mock_start, mock_push_and_send) -> None: - mock_start.return_value = None - mock_init.return_value = self.dummy_process3 - mock_push_and_send.return_value = None - self.test_manager._parent_id_process_dict = \ - self.config_process_dict_example + "_create_and_start_alerter_process") + @mock.patch.object(SystemAlertersManager, "_send_heartbeat") + def test_process_ping_sends_a_valid_hb( + self, is_alive_side_effect, dead_alerters, mock_send_hb, + mock_create_and_start, mock_is_alive, mock_join) -> None: + mock_send_hb.return_value = None + mock_join.return_value = None + mock_create_and_start.return_value = None + mock_is_alive.side_effect = is_alive_side_effect + + self.test_manager._alerter_process_dict = \ + self.alerter_process_dict_example + + # Some of the variables below are needed as parameters for the + # process_ping function + self.test_manager._initialise_rabbitmq() + blocking_channel = self.test_manager.rabbitmq.channel + method = pika.spec.Basic.Deliver(routing_key=PING_ROUTING_KEY) + body = 'ping' + properties = pika.spec.BasicProperties() + + self.test_manager._process_ping(blocking_channel, method, properties, + body) + + expected_hb = { + 'component_name': self.manager_name, + 'running_processes': [ + alerter + for alerter in self.alerter_process_dict_example.keys() + if alerter not in dead_alerters + ], + 'dead_processes': dead_alerters, + 'timestamp': datetime.now().timestamp() + } + mock_send_hb.assert_called_once_with(expected_hb) + + @parameterized.expand([ + ([True, True], False,), + ([True, False], True,), + ([False, True], True,), + ([False, False], True,), + ]) + @freeze_time("2012-01-01") + @mock.patch.object(multiprocessing.Process, "join") + @mock.patch.object(multiprocessing.Process, "is_alive") + @mock.patch.object(SystemAlertersManager, + "_create_and_start_alerter_process") + @mock.patch.object(SystemAlertersManager, "_send_heartbeat") + def test_process_ping_restarts_dead_processes_correctly( + self, is_alive_side_effect, expected_restart, mock_send_hb, + mock_create_and_start, mock_is_alive, mock_join) -> None: + mock_send_hb.return_value = None + mock_join.return_value = None + mock_create_and_start.return_value = None + mock_is_alive.side_effect = is_alive_side_effect - self.expected_output[self.parent_id_3] = {} + self.test_manager._alerter_process_dict = \ + self.alerter_process_dict_example - new_entry = self.expected_output[self.parent_id_3] - new_entry['component_name'] = SYSTEM_ALERTER_NAME_TEMPLATE.format( - self.chain_3) - new_entry['chain'] = self.chain_3 - new_entry['process'] = self.dummy_process3 + # Some of the variables below are needed as parameters for the + # process_ping function + self.test_manager._initialise_rabbitmq() + blocking_channel = self.test_manager.rabbitmq.channel + method = pika.spec.Basic.Deliver(routing_key=PING_ROUTING_KEY) + body = 'ping' + properties = pika.spec.BasicProperties() - self.test_manager._create_and_start_alerter_process( - self.system_alerts_config, self.parent_id_3, - self.chain_3) + self.test_manager._process_ping(blocking_channel, method, properties, + body) - self.assertEqual(self.expected_output, - self.test_manager.parent_id_process_dict) + if expected_restart: + mock_create_and_start.assert_called_once() + else: + mock_create_and_start.assert_not_called() - @mock.patch.object(SystemAlertersManager, - "_push_latest_data_to_queue_and_send") - @mock.patch.object(multiprocessing.Process, "start") - def test_create_and_start_alerter_process_creates_the_correct_process( - self, mock_start, mock_push_and_send) -> None: - mock_start.return_value = None - mock_push_and_send.return_value = None + @mock.patch.object(multiprocessing.Process, "is_alive") + @mock.patch.object(SystemAlertersManager, "_send_heartbeat") + def test_process_ping_does_not_send_hb_if_processing_fails( + self, mock_send_hb, mock_is_alive) -> None: + mock_is_alive.side_effect = self.test_exception + mock_send_hb.return_value = None + self.test_manager._alerter_process_dict = \ + self.alerter_process_dict_example - self.test_manager._create_and_start_alerter_process( - self.system_alerts_config, self.parent_id_3, - self.chain_3) + # Some of the variables below are needed as parameters for the + # process_ping function + self.test_manager._initialise_rabbitmq() + blocking_channel = self.test_manager.rabbitmq.channel + method = pika.spec.Basic.Deliver(routing_key=PING_ROUTING_KEY) + body = 'ping' + properties = pika.spec.BasicProperties() - new_entry = self.test_manager.parent_id_process_dict[self.parent_id_3] - new_entry_process = new_entry['process'] - self.assertTrue(new_entry_process.daemon) - self.assertEqual(2, len(new_entry_process._args)) - self.assertEqual(self.system_alerts_config, new_entry_process._args[0]) - self.assertEqual(self.chain_3, new_entry_process._args[1]) - self.assertEqual(start_system_alerter, new_entry_process._target) + self.test_manager._process_ping(blocking_channel, method, + properties, body) - @mock.patch.object(multiprocessing.Process, "start") - @mock.patch.object(SystemAlertersManager, - "_push_latest_data_to_queue_and_send") - @mock.patch("src.alerter.alerter_starters.create_logger") - def test_create_and_start_alerter_process_starts_the_process( - self, mock_create_logger, mock_push_and_send, mock_start) -> None: - mock_create_logger.return_value = self.dummy_logger - mock_push_and_send.return_value = None - mock_start.return_value = None - - self.test_manager._create_and_start_alerter_process( - self.system_alerts_config, self.parent_id_3, - self.chain_3) + mock_send_hb.assert_not_called() - mock_start.assert_called_once() + def test_proc_ping_send_hb_does_not_raise_msg_not_del_exce_if_hb_not_routed( + self) -> None: + """ + In this test we are assuming that no configs have been set, this is done + to keep the test as simple as possible. We are also assuming that a + MsgWasNotDeliveredException will be raised automatically because we are + deleting the HealthExchange after every test, and thus there are no + consumers of the heartbeat. + """ + self.test_manager._initialise_rabbitmq() + blocking_channel = self.test_manager.rabbitmq.channel + method = pika.spec.Basic.Deliver(routing_key=PING_ROUTING_KEY) + body = 'ping' + properties = pika.spec.BasicProperties() + try: + self.test_manager._process_ping(blocking_channel, method, + properties, body) + except MessageWasNotDeliveredException: + self.fail('A MessageWasNotDeliveredException should not have been ' + 'raised') + + @parameterized.expand([ + (pika.exceptions.AMQPConnectionError, + pika.exceptions.AMQPConnectionError('test'),), + (pika.exceptions.AMQPChannelError, + pika.exceptions.AMQPChannelError('test'),), + (Exception, Exception('test'),), + ]) + @mock.patch.object(SystemAlertersManager, "_send_heartbeat") + def test_process_ping_raises_unrecognised_error_if_raised_by_send_heartbeat( + self, exception_class, exception_instance, mock_send_hb) -> None: + mock_send_hb.side_effect = exception_instance + + self.test_manager._initialise_rabbitmq() + blocking_channel = self.test_manager.rabbitmq.channel + method = pika.spec.Basic.Deliver(routing_key=PING_ROUTING_KEY) + body = 'ping' + properties = pika.spec.BasicProperties() + + self.assertRaises(exception_class, self.test_manager._process_ping, + blocking_channel, method, properties, body) + + @parameterized.expand([ + ({}, False,), + ('self.alerter_process_dict_example', True) + ]) @freeze_time("2012-01-01") - @mock.patch.object(multiprocessing.Process, "start") @mock.patch.object(SystemAlertersManager, "_push_latest_data_to_queue_and_send") - @mock.patch("src.alerter.alerter_starters.create_logger") - def test_create_and_start_alerter_process_sends_a_component_reset_alert( - self, mock_create_logger, mock_push_and_send, mock_start) -> None: - mock_create_logger.return_value = self.dummy_logger - mock_push_and_send.return_value = None + @mock.patch.object(multiprocessing.Process, "start") + def test_create_and_start_alerter_processes_if_processes_not_running( + self, state, state_is_str, mock_start, mock_push_and_send) -> None: + """ + In this test we will check that the required processes are created and + started, and that a reset alert is sent. We will perform this test for + both when the function is executed for the first time (empty state), and + for when the process is dead (state non-empty but dummy process not + running by default) + """ + self.test_manager._alerter_process_dict = eval( + state) if state_is_str else state mock_start.return_value = None + mock_push_and_send.return_value = None - self.test_manager._create_and_start_alerter_process( - self.system_alerts_config, self.parent_id_3, - self.chain_3) + self.test_manager._create_and_start_alerter_process() - test_alert = ComponentResetAlert( - SYSTEM_ALERTER_NAME_TEMPLATE.format(self.chain_3), - datetime.now().timestamp(), SystemAlerter.__name__, - self.parent_id_3, self.chain_3) - mock_push_and_send.assert_called_once_with(test_alert.alert_data) + new_entry_process = self.test_manager.alerter_process_dict[ + SYSTEM_ALERTER_NAME] - @mock.patch.object(SystemAlertersManager, - "_create_and_start_alerter_process") - @mock.patch("src.alerter.managers.system.SystemAlertsConfig") - @mock.patch.object(RabbitMQApi, "basic_ack") - def test_process_configs_ignores_default_key(self, mock_ack, - mock_alerts_config, - mock_create_start) -> None: - # This test will pass if the stored systems config does not change. - # This would mean that the DEFAULT key was ignored, otherwise, it would - # have been included as a new config. - mock_create_start.return_value = None - mock_ack.return_value = None - try: - # Must create a connection so that the blocking channel is passed - self.test_manager.rabbitmq.connect() - blocking_channel = self.test_manager.rabbitmq.channel - method_chains = pika.spec.Basic.Deliver( - routing_key=self.chains_routing_key) - method_general = pika.spec.Basic.Deliver( - routing_key=self.general_routing_key) - body_chain = json.dumps(self.sent_configs_example_with_default) - body_general = json.dumps(self.sent_configs_example_with_default) - properties = pika.spec.BasicProperties() - - # We will send the message twice with both general and chain - # routing keys to make sure that the DEFAULT key is ignored in both - # cases - self.test_manager._process_configs(blocking_channel, method_general, - properties, body_general) - mock_alerts_config.assert_called_once_with( - parent_id=self.parent_id_1, - open_file_descriptors=self.open_file_descriptors, - system_cpu_usage=self.system_cpu_usage, - system_storage_usage=self.system_storage_usage, - system_ram_usage=self.system_ram_usage, - system_is_down=self.system_is_down - ) - self.test_manager._process_configs(blocking_channel, method_chains, - properties, body_chain) - self.assertEqual(2, mock_alerts_config.call_count) - mock_alerts_config.assert_called_with( - parent_id=self.parent_id_1, - open_file_descriptors=self.open_file_descriptors, - system_cpu_usage=self.system_cpu_usage, - system_storage_usage=self.system_storage_usage, - system_ram_usage=self.system_ram_usage, - system_is_down=self.system_is_down - ) - except Exception as e: - self.fail("Test failed: {}".format(e)) - - self.assertEqual(2, mock_ack.call_count) + # Check that the process was created correctly + self.assertTrue(new_entry_process.daemon) + self.assertEqual(1, len(new_entry_process._args)) + self.assertEqual(self.test_manager.system_alerts_config_factory, + new_entry_process._args[0]) + self.assertEqual(start_system_alerter, new_entry_process._target) - @mock.patch("src.alerter.managers.system.SystemAlertsConfig") - @mock.patch.object(RabbitMQApi, "basic_ack") - @mock.patch.object(SystemAlertersManager, - "_create_and_start_alerter_process") - def test_process_configs_stores_new_configs_to_be_alerted_correctly( - self, startup_mock, mock_ack, mock_system_alerts_config) -> None: + # Check that the process was started + mock_start.assert_called_once() - mock_ack.return_value = None - startup_mock.return_value = None + # Check that a reset alert was sent + expected_alert = ComponentResetAlert( + SYSTEM_ALERTER_NAME, datetime.now().timestamp(), + SystemAlerter.__name__) + mock_push_and_send.assert_called_once_with( + expected_alert.alert_data, SYSTEM_ALERT_ROUTING_KEY) - try: - # Must create a connection so that the blocking channel is passed - self.test_manager.rabbitmq.connect() - blocking_channel = self.test_manager.rabbitmq.channel - - # We will send new configs through both the existing and - # non-existing chain and general paths to make sure that all routes - # work as expected. - method_chains = pika.spec.Basic.Deliver( - routing_key=self.chains_routing_key) - method_general = pika.spec.Basic.Deliver( - routing_key=self.general_routing_key) - body_chain_initial = json.dumps( - self.sent_configs_example_with_default) - body_general_initial = json.dumps( - self.sent_configs_example_with_default_2) - properties = pika.spec.BasicProperties() - - self.test_manager._process_configs(blocking_channel, method_chains, - properties, body_chain_initial) - - call_1 = call(parent_id=self.parent_id_1, - open_file_descriptors=self.open_file_descriptors, - system_cpu_usage=self.system_cpu_usage, - system_storage_usage=self.system_storage_usage, - system_ram_usage=self.system_ram_usage, - system_is_down=self.system_is_down) - - mock_system_alerts_config.assert_has_calls([call_1]) - - self.test_manager._process_configs(blocking_channel, method_general, - properties, body_general_initial) - call_2 = call(parent_id=self.parent_id_2, - open_file_descriptors=self.open_file_descriptors_2, - system_cpu_usage=self.system_cpu_usage_2, - system_storage_usage=self.system_storage_usage_2, - system_ram_usage=self.system_ram_usage_2, - system_is_down=self.system_is_down_2) - - mock_system_alerts_config.assert_has_calls([call_2]) - - self.open_file_descriptors['enabled'] = str( - not bool(self.enabled_alert)) - self.open_file_descriptors_2['enabled'] = str( - not bool(self.enabled_alert)) - self.sent_configs_example_with_default[ - '1'] = self.open_file_descriptors - self.sent_configs_example_with_default_2[ - '1'] = self.open_file_descriptors_2 - - body_new_configs_chain = json.dumps( - self.sent_configs_example_with_default) - body_new_configs_general = json.dumps( - self.sent_configs_example_with_default_2) - self.test_manager._process_configs(blocking_channel, method_chains, - properties, - body_new_configs_chain) - call_3 = call(parent_id=self.parent_id_1, - open_file_descriptors=self.open_file_descriptors, - system_cpu_usage=self.system_cpu_usage, - system_storage_usage=self.system_storage_usage, - system_ram_usage=self.system_ram_usage, - system_is_down=self.system_is_down) - mock_system_alerts_config.assert_has_calls([call_3]) - self.test_manager._process_configs(blocking_channel, method_general, - properties, - body_new_configs_general) - call_4 = call(parent_id=self.parent_id_2, - open_file_descriptors=self.open_file_descriptors_2, - system_cpu_usage=self.system_cpu_usage_2, - system_storage_usage=self.system_storage_usage_2, - system_ram_usage=self.system_ram_usage_2, - system_is_down=self.system_is_down_2) - mock_system_alerts_config.assert_has_calls([call_4]) - self.assertEqual(4, mock_system_alerts_config.call_count) - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.managers.system.SystemAlertsConfig") @mock.patch.object(SystemAlertersManager, "_push_latest_data_to_queue_and_send") - @mock.patch.object(RabbitMQApi, "basic_ack") + @mock.patch.object(multiprocessing, "Process") + @mock.patch.object(multiprocessing.Process, "is_alive") @mock.patch.object(multiprocessing.Process, "start") - @mock.patch.object(multiprocessing.Process, "terminate") - @mock.patch.object(multiprocessing.Process, "join") - def test_process_configs_stores_modified_configs_to_be_alerted_on_correctly( - self, mock_join, mock_terminate, mock_start, mock_ack, - mock_push_and_send, mock_system_alerts_config) -> None: - - mock_ack.return_value = None - mock_start.return_value = None - mock_join.return_value = None - mock_terminate.return_value = None - mock_push_and_send.return_value = None - - try: - # Must create a connection so that the blocking channel is passed - self.test_manager.rabbitmq.connect() - blocking_channel = self.test_manager.rabbitmq.channel - - # We will send new configs through both the existing and - # non-existing chain and general paths to make sure that all routes - # work as expected. - method_chains = pika.spec.Basic.Deliver( - routing_key=self.chains_routing_key) - method_general = pika.spec.Basic.Deliver( - routing_key=self.general_routing_key) - body_chain_initial = json.dumps( - self.sent_configs_example_with_default) - body_general_initial = json.dumps( - self.sent_configs_example_with_default_2) - properties = pika.spec.BasicProperties() - - self.test_manager._process_configs(blocking_channel, method_chains, - properties, body_chain_initial) - mock_join.assert_not_called() - mock_terminate.assert_not_called() - self.test_manager._process_configs(blocking_channel, method_general, - properties, body_general_initial) - mock_join.assert_not_called() - mock_terminate.assert_not_called() - - self.open_file_descriptors['enabled'] = str( - not bool(self.enabled_alert)) - self.open_file_descriptors_2['enabled'] = str( - not bool(self.enabled_alert)) - self.sent_configs_example_with_default[ - '1'] = self.open_file_descriptors - self.sent_configs_example_with_default_2[ - '1'] = self.open_file_descriptors_2 - - body_new_configs_chain = json.dumps( - self.sent_configs_example_with_default) - body_new_configs_general = json.dumps( - self.sent_configs_example_with_default_2) - self.test_manager._process_configs(blocking_channel, method_chains, - properties, - body_new_configs_chain) - self.assertEqual(1, mock_join.call_count) - self.assertEqual(1, mock_terminate.call_count) - - self.test_manager._process_configs(blocking_channel, method_general, - properties, - body_new_configs_general) - self.assertEqual(2, mock_join.call_count) - self.assertEqual(2, mock_terminate.call_count) - self.assertTrue( - self.parent_id_1 in self.test_manager.parent_id_process_dict) - self.assertTrue( - self.parent_id_2 in self.test_manager.parent_id_process_dict) - self.assertEqual(4, mock_system_alerts_config.call_count) - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch.object(SystemAlertersManager, - "_push_latest_data_to_queue_and_send") - @mock.patch("src.alerter.managers.system.SystemAlertsConfig") - @mock.patch.object(RabbitMQApi, "basic_ack") - @mock.patch.object(SystemAlertersManager, - "_create_and_start_alerter_process") - def test_proc_configs_starts_new_alerters_for_new_configs_to_be_alerted_on( - self, startup_mock, mock_ack, mock_system_alerters_config, + def test_create_and_start_alerter_proc_does_nothing_if_proc_running( + self, mock_start, mock_is_alive, mock_init_proc, mock_push_and_send) -> None: - - mock_system_alerters_config_1 = mock_system_alerters_config( - parent_id=self.parent_id_1, - open_file_descriptors=self.open_file_descriptors, - system_cpu_usage=self.system_cpu_usage, - system_storage_usage=self.system_storage_usage, - system_ram_usage=self.system_ram_usage, - system_is_down=self.system_is_down) - mock_system_alerters_config_2 = mock_system_alerters_config( - parent_id=self.parent_id_2, - open_file_descriptors=self.open_file_descriptors_2, - system_cpu_usage=self.system_cpu_usage_2, - system_storage_usage=self.system_storage_usage_2, - system_ram_usage=self.system_ram_usage_2, - system_is_down=self.system_is_down_2) - mock_ack.return_value = None - startup_mock.return_value = None + """ + In this test we will check that no process is created or started, and + that no reset alert is sent. + """ + self.test_manager._alerter_process_dict = \ + self.alerter_process_dict_example + mock_start.return_value = None + mock_is_alive.return_value = True + mock_init_proc.return_value = None mock_push_and_send.return_value = None - try: - # Must create a connection so that the blocking channel is passed - self.test_manager.rabbitmq.connect() - blocking_channel = self.test_manager.rabbitmq.channel - - # We will send new configs through both the existing and - # non-existing chain and general paths to make sure that all routes - # work as expected. - method_chains = pika.spec.Basic.Deliver( - routing_key=self.chains_routing_key) - method_general = pika.spec.Basic.Deliver( - routing_key=self.general_routing_key) - body_chain_initial = json.dumps( - self.sent_configs_example_with_default) - body_general_initial = json.dumps( - self.sent_configs_example_with_default_2) - properties = pika.spec.BasicProperties() - - self.test_manager._process_configs(blocking_channel, method_chains, - properties, body_chain_initial) - self.assertEqual(1, startup_mock.call_count) - startup_mock.assert_called_once_with( - mock_system_alerters_config_1, self.parent_id_1, - self.chain_1 - ) - self.test_manager._process_configs(blocking_channel, method_general, - properties, - body_general_initial) - self.assertEqual(2, startup_mock.call_count) - startup_mock.assert_called_with( - mock_system_alerters_config_2, self.parent_id_2, - self.chain_2 - ) - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch.object(SystemAlertersManager, - "_push_latest_data_to_queue_and_send") - @mock.patch("src.alerter.alerter_starters.create_logger") - @mock.patch.object(RabbitMQApi, "basic_ack") - def test_proc_confs_term_and_starts_alerters_for_modified_confs_to_be_alerted_on( - self, mock_ack, mock_create_logger, mock_push_and_send) -> None: + self.test_manager._create_and_start_alerter_process() - mock_ack.return_value = None - mock_create_logger.return_value = self.dummy_logger - mock_push_and_send.return_value = None - try: - # Must create a connection so that the blocking channel is passed - self.test_manager.rabbitmq.connect() - blocking_channel = self.test_manager.rabbitmq.channel - - # We will send new configs through both the existing and - # non-existing chain and general paths to make sure that all routes - # work as expected. - method_chains = pika.spec.Basic.Deliver( - routing_key=self.chains_routing_key) - method_general = pika.spec.Basic.Deliver( - routing_key=self.general_routing_key) - body_chain_initial = json.dumps( - self.sent_configs_example_with_default) - body_general_initial = json.dumps( - self.sent_configs_example_with_default_2) - properties = pika.spec.BasicProperties() - - # First send the new configs as the state is empty - self.test_manager._process_configs(blocking_channel, method_chains, - properties, body_chain_initial) - self.test_manager._process_configs(blocking_channel, method_general, - properties, body_general_initial) - - # Assure that the processes have been started - self.assertTrue(self.test_manager.parent_id_process_dict[ - self.parent_id_1]['process'].is_alive()) - self.assertTrue(self.test_manager.parent_id_process_dict[ - self.parent_id_2]['process'].is_alive()) - - # Give some time till the process starts - time.sleep(1) - - parent_id_1_old_proc = self.test_manager.parent_id_process_dict[ - self.parent_id_1]['process'] - parent_id_2_old_proc = self.test_manager.parent_id_process_dict[ - self.parent_id_2]['process'] - - self.open_file_descriptors['enabled'] = str( - not bool(self.enabled_alert)) - self.open_file_descriptors_2['enabled'] = str( - not bool(self.enabled_alert)) - self.sent_configs_example_with_default[ - '1'] = self.open_file_descriptors - self.sent_configs_example_with_default_2[ - '1'] = self.open_file_descriptors_2 - - body_new_configs_chain = json.dumps( - self.sent_configs_example_with_default) - body_new_configs_general = json.dumps( - self.sent_configs_example_with_default_2) - self.test_manager._process_configs(blocking_channel, method_chains, - properties, - body_new_configs_chain) - self.test_manager._process_configs(blocking_channel, method_general, - properties, - body_new_configs_general) - - # Give some time till the process re-starts - time.sleep(1) - - # Check that the old process has terminated and a new one has - # started. - self.assertFalse(parent_id_1_old_proc.is_alive()) - self.assertTrue(self.test_manager.parent_id_process_dict[ - self.parent_id_1]['process'].is_alive()) - self.assertFalse(parent_id_2_old_proc.is_alive()) - self.assertTrue(self.test_manager.parent_id_process_dict[ - self.parent_id_2]['process'].is_alive()) - - # Clean before finishing - self.test_manager.parent_id_process_dict[self.parent_id_1][ - 'process'].terminate() - self.test_manager.parent_id_process_dict[self.parent_id_1][ - 'process'].join() - self.test_manager.parent_id_process_dict[self.parent_id_2][ - 'process'].terminate() - self.test_manager.parent_id_process_dict[self.parent_id_2][ - 'process'].join() - except Exception as e: - self.fail("Test failed: {}".format(e)) + mock_push_and_send.assert_not_called() + mock_init_proc.assert_not_called() + mock_start.assert_not_called() + @freeze_time("2012-01-01") + @mock.patch.object(RabbitMQApi, 'basic_ack') @mock.patch.object(SystemAlertersManager, "_push_latest_data_to_queue_and_send") - @mock.patch("src.alerter.alerter_starters.create_logger") - @mock.patch.object(RabbitMQApi, "basic_ack") - def test_proc_configs_term_and_stops_alerters_for_removed_configs( - self, mock_ack, mock_create_logger, mock_push_and_send) -> None: - + def test_process_configs_if_non_empty_configs_received( + self, mock_push_and_send, mock_ack) -> None: + """ + In this test we will check that if non-empty configs are received, + the process_configs function stores the received configs and sends a + reset alert + """ mock_ack.return_value = None mock_push_and_send.return_value = None - mock_create_logger.return_value = self.dummy_logger - try: - # Must create a connection so that the blocking channel is passed - self.test_manager.rabbitmq.connect() - blocking_channel = self.test_manager.rabbitmq.channel - - # We will send new configs through both the existing and - # non-existing chain and general paths to make sure that all routes - # work as expected. - method_chains = pika.spec.Basic.Deliver( - routing_key=self.chains_routing_key) - method_general = pika.spec.Basic.Deliver( - routing_key=self.general_routing_key) - body_chain_initial = json.dumps( - self.sent_configs_example_with_default) - body_general_initial = json.dumps( - self.sent_configs_example_with_default_2) - properties = pika.spec.BasicProperties() - - # First send the new configs as the state is empty - self.test_manager._process_configs(blocking_channel, method_chains, - properties, body_chain_initial) - self.test_manager._process_configs(blocking_channel, method_general, - properties, body_general_initial) - - # Assure that the processes have been started - self.assertTrue(self.test_manager.parent_id_process_dict[ - self.parent_id_1]['process'].is_alive()) - self.assertTrue(self.test_manager.parent_id_process_dict[ - self.parent_id_2]['process'].is_alive()) - - # Give some time till the process starts - time.sleep(1) - - parent_id_1_old_proc = self.test_manager.parent_id_process_dict[ - self.parent_id_1]['process'] - parent_id_2_old_proc = self.test_manager.parent_id_process_dict[ - self.parent_id_2]['process'] - - body_new_configs_chain = json.dumps(self.empty_message) - body_new_configs_general = json.dumps(self.empty_message) - self.test_manager._process_configs(blocking_channel, method_chains, - properties, - body_new_configs_chain) - self.test_manager._process_configs(blocking_channel, method_general, - properties, - body_new_configs_general) - - # Give some time till the process re-starts - time.sleep(1) - - # Check that the old process has terminated and a new one has - # started. - self.assertFalse(parent_id_1_old_proc.is_alive()) - self.assertFalse(parent_id_2_old_proc.is_alive()) - self.assertFalse( - self.parent_id_1 in self.test_manager.parent_id_process_dict) - self.assertFalse( - self.parent_id_1 in self.test_manager.systems_alerts_configs) - self.assertFalse( - self.parent_id_2 in self.test_manager.parent_id_process_dict) - self.assertFalse( - self.parent_id_2 in self.test_manager.systems_alerts_configs) - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch("src.alerter.managers.system.SystemAlertsConfig") - @mock.patch.object(RabbitMQApi, "basic_ack") - @mock.patch.object(SystemAlertersManager, - "_create_and_start_alerter_process") - @mock.patch.object(multiprocessing.Process, "join") - @mock.patch.object(multiprocessing.Process, "terminate") - def test_process_confs_restarts_an_updated_alerter_with_the_correct_conf( - self, mock_terminate, mock_join, startup_mock, mock_ack, - mock_system_alerters_config) -> None: - mock_ack.return_value = None - startup_mock.return_value = None - mock_join.return_value = None - mock_terminate.return_value = None + blocking_channel = self.test_manager.rabbitmq.channel + method_chains = pika.spec.Basic.Deliver( + routing_key=self.chains_routing_key) + body = json.dumps(self.config_1) + properties = pika.spec.BasicProperties() + parsed_routing_key = self.chains_routing_key.split('.') + chain_name = parsed_routing_key[1] + ' ' + parsed_routing_key[2] - self.test_manager._systems_alerts_configs[self.parent_id_1] = \ - self.system_alerts_config - self.test_manager._systems_alerts_configs[self.parent_id_2] = \ - self.system_alerts_config_2 - self.test_manager._parent_id_process_dict = \ - self.config_process_dict_example + self.test_manager._process_configs(blocking_channel, method_chains, + properties, body) - try: - # Must create a connection so that the blocking channel is passed - self.test_manager.rabbitmq.connect() - blocking_channel = self.test_manager.rabbitmq.channel - - # We will send new configs through both the existing and - # non-existing chain and general paths to make sure that all routes - # work as expected. - method_chains = pika.spec.Basic.Deliver( - routing_key=self.chains_routing_key) - method_general = pika.spec.Basic.Deliver( - routing_key=self.general_routing_key) - - self.open_file_descriptors['enabled'] = str( - not bool(self.enabled_alert)) - self.open_file_descriptors_2['enabled'] = str( - not bool(self.enabled_alert)) - self.sent_configs_example_with_default[ - '1'] = self.open_file_descriptors - self.sent_configs_example_with_default_2[ - '1'] = self.open_file_descriptors_2 - - mock_system_alerters_config_1 = mock_system_alerters_config( + expected_configs = { + chain_name: SystemAlertsConfig( parent_id=self.parent_id_1, - open_file_descriptors=self.open_file_descriptors, - system_cpu_usage=self.system_cpu_usage, - system_storage_usage=self.system_storage_usage, - system_ram_usage=self.system_ram_usage, - system_is_down=self.system_is_down) - - mock_system_alerters_config_2 = mock_system_alerters_config( - parent_id=self.parent_id_2, - open_file_descriptors=self.open_file_descriptors_2, - system_cpu_usage=self.system_cpu_usage_2, - system_storage_usage=self.system_storage_usage_2, - system_ram_usage=self.system_ram_usage_2, - system_is_down=self.system_is_down_2) - - body_updated_configs_chain = json.dumps( - self.sent_configs_example_with_default) - body_updated_configs_general = json.dumps( - self.sent_configs_example_with_default_2) - - properties = pika.spec.BasicProperties() - - self.test_manager._process_configs(blocking_channel, method_chains, - properties, - body_updated_configs_chain) - startup_mock.assert_called_with( - mock_system_alerters_config_1, self.parent_id_1, - self.chain_1 + open_file_descriptors=self.config_1['1'], + system_cpu_usage=self.config_1['2'], + system_storage_usage=self.config_1['3'], + system_ram_usage=self.config_1['4'], + system_is_down=self.config_1['5'], ) + } + expected_alert = ComponentResetAlert( + SYSTEM_ALERTER_NAME, datetime.now().timestamp(), + SystemAlerter.__name__, self.parent_id_1, chain_name + ) - self.test_manager._process_configs(blocking_channel, method_general, - properties, - body_updated_configs_general) - - startup_mock.assert_called_with( - mock_system_alerters_config_2, self.parent_id_2, - self.chain_2 - ) - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch.object(SystemAlertersManager, - "_push_latest_data_to_queue_and_send") - @mock.patch.object(RabbitMQApi, "basic_ack") - def test_process_configs_ignores_new_configs_with_missing_keys( - self, mock_ack, mock_push_and_send) -> None: - # We will check whether the state is kept intact if new configurations - # with missing keys are sent. Exceptions should never be raised in this - # case, and basic_ack must be called to ignore the message. - mock_ack.return_value = None - mock_push_and_send.return_value = None - try: - # Must create a connection so that the blocking channel is passed - self.test_manager.rabbitmq.connect() - blocking_channel = self.test_manager.rabbitmq.channel - - # We will send new configs through both the existing and - # non-existing chain and general paths to make sure that all routes - # work as expected. - method_chains = pika.spec.Basic.Deliver( - routing_key=self.chains_routing_key) - method_general = pika.spec.Basic.Deliver( - routing_key=self.general_routing_key) - body_new_configs_general = json.dumps( - self.sent_configs_example_with_default_2) - body_new_configs_chain_missing = json.dumps( - self.sent_configs_example_with_missing_keys) - properties = pika.spec.BasicProperties() - - # This should start a process as normal - self.test_manager._process_configs(blocking_channel, method_general, - properties, - body_new_configs_general) - self.assertEqual(1, mock_ack.call_count) - self.assertTrue( - self.parent_id_2 in self.test_manager.systems_alerts_configs) - - # This should fail to start a process as there are missing keys - self.test_manager._process_configs(blocking_channel, method_chains, - properties, - body_new_configs_chain_missing) - self.assertEqual(2, mock_ack.call_count) - self.assertFalse( - self.parent_id_1 in self.test_manager.systems_alerts_configs) - - self.test_manager._terminate_and_join_chain_alerter_processes( - self.parent_id_2) - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch.object(SystemAlertersManager, - "_push_latest_data_to_queue_and_send") - @mock.patch.object(RabbitMQApi, "basic_ack") - def test_process_configs_ignores_modified_configs_with_missing_keys( - self, mock_ack, mock_push_and_send) -> None: - # We will check whether the state is kept intact if modified - # configurations with missing keys are sent. Exceptions should never be - # raised in this case, and basic_ack must be called to ignore the - # message. - mock_ack.return_value = None - mock_push_and_send.return_value = None - self.test_manager._systems_alerts_configs[self.parent_id_1] = \ - self.system_alerts_config - self.test_manager._systems_alerts_configs[self.parent_id_2] = \ - self.system_alerts_config_2 - self.test_manager._parent_id_process_dict = \ - self.config_process_dict_example - try: - # Must create a connection so that the blocking channel is passed - self.test_manager.rabbitmq.connect() - blocking_channel = self.test_manager.rabbitmq.channel - - # We will send new configs through both the existing and - # non-existing chain and general paths to make sure that all routes - # work as expected. - method_chains = pika.spec.Basic.Deliver( - routing_key=self.chains_routing_key) - method_general = pika.spec.Basic.Deliver( - routing_key=self.general_routing_key) - body_updated_configs_chain = json.dumps( - self.sent_configs_example_with_missing_keys) - body_updated_configs_general = json.dumps( - self.sent_configs_example_with_default_2_missing_keys) - properties = pika.spec.BasicProperties() - - self.test_manager._process_configs(blocking_channel, method_general, - properties, - body_updated_configs_general) - self.assertEqual(1, mock_ack.call_count) - self.assertEqual(self.config_process_dict_example, - self.test_manager.parent_id_process_dict) - self.assertEqual(self.system_alerts_config, - self.test_manager.systems_alerts_configs[ - self.parent_id_1]) - - self.test_manager._process_configs(blocking_channel, method_chains, - properties, - body_updated_configs_chain) - self.assertEqual(2, mock_ack.call_count) - self.assertEqual(self.config_process_dict_example, - self.test_manager.parent_id_process_dict) - self.assertEqual(self.system_alerts_config_2, - self.test_manager.systems_alerts_configs[ - self.parent_id_2]) - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch.object(SystemAlertersManager, - "_push_latest_data_to_queue_and_send") - @mock.patch.object(RabbitMQApi, "basic_nack") - @mock.patch.object(RabbitMQApi, "basic_ack") - def test_process_configs_ignores_confs_if_ComponentResetAlert_fails( - self, mock_ack, mock_nack, mock_push_and_send) -> None: - # We will check whether the state is kept intact if a - # ComponentResetAlert fails in being delivered. Exceptions should never - # be raised in this case, and basic_nack must be called so the message - # is re-delivered. - mock_nack.return_value = None - mock_ack.return_value = None - mock_push_and_send.side_effect = [ - None, MessageWasNotDeliveredException('test') - ] - try: - # Must create a connection so that the blocking channel is passed - self.test_manager.rabbitmq.connect() - blocking_channel = self.test_manager.rabbitmq.channel - - # We will send new configs through both the existing and - # non-existing chain and general paths to make sure that all routes - # work as expected. - method_chains = pika.spec.Basic.Deliver( - routing_key=self.chains_routing_key) - method_general = pika.spec.Basic.Deliver( - routing_key=self.general_routing_key) - body_new_configs_general = json.dumps( - self.sent_configs_example_with_default_2) - body_new_configs_chain = json.dumps( - self.sent_configs_example_with_default) - properties = pika.spec.BasicProperties() - - # This should start a process as normal - self.test_manager._process_configs(blocking_channel, method_general, - properties, - body_new_configs_general) - self.assertEqual(1, mock_ack.call_count) - self.assertTrue( - self.parent_id_2 in self.test_manager.systems_alerts_configs) - - # This should fail to start a process as we will automate a - # MessageWasNotDeliveredException - self.test_manager._process_configs(blocking_channel, method_chains, - properties, - body_new_configs_chain) - self.assertEqual(1, mock_ack.call_count) - self.assertFalse( - self.parent_id_1 in self.test_manager.systems_alerts_configs) - self.assertEqual(1, mock_nack.call_count) - - self.test_manager._terminate_and_join_chain_alerter_processes( - self.parent_id_2) - except Exception as e: - self.fail("Test failed: {}".format(e)) + self.assertEqual(expected_configs, + self.test_manager.system_alerts_config_factory.configs) + mock_push_and_send.assert_called_once_with( + expected_alert.alert_data, SYSTEM_ALERT_ROUTING_KEY) + mock_ack.assert_called_once() @freeze_time("2012-01-01") + @mock.patch.object(RabbitMQApi, 'basic_ack') @mock.patch.object(SystemAlertersManager, "_push_latest_data_to_queue_and_send") - @mock.patch.object(RabbitMQApi, "basic_ack") - @mock.patch.object(multiprocessing.Process, "is_alive") - @mock.patch.object(multiprocessing.Process, "start") - @mock.patch.object(multiprocessing.Process, "join") - @mock.patch.object(multiprocessing.Process, "terminate") - def test_process_ping_sends_a_valid_hb_if_all_processes_are_alive( - self, mock_terminate, mock_join, mock_start, mock_is_alive, - mock_ack, mock_push_and_send) -> None: - # This test creates a queue which receives messages with the same - # routing key as the ones sent by send_heartbeat, and checks that the - # received heartbeat is valid. + def test_process_configs_if_non_empty_general_configs_received( + self, mock_push_and_send, mock_ack) -> None: + """ + In this test we will check that if non-empty general configs are + received, the process_configs function stores the received configs + and sends a reset alert + """ mock_ack.return_value = None - mock_is_alive.side_effect = [True, True] - mock_start.return_value = None - mock_join.return_value = None - mock_terminate.return_value = None mock_push_and_send.return_value = None - try: - self.test_manager._initialise_rabbitmq() - blocking_channel = self.test_manager.rabbitmq.channel - method_chains = pika.spec.Basic.Deliver( - routing_key=self.chains_routing_key) - method_general = pika.spec.Basic.Deliver( - routing_key=self.general_routing_key) - body_chain_initial = json.dumps( - self.sent_configs_example_with_default) - body_general_initial = json.dumps( - self.sent_configs_example_with_default_2) - properties = pika.spec.BasicProperties() - - # First send the new configs as the state is empty - self.test_manager._process_configs(blocking_channel, method_chains, - properties, body_chain_initial) - self.test_manager._process_configs(blocking_channel, method_general, - properties, body_general_initial) - - # Delete the queue before to avoid messages in the queue on error. - self.test_manager.rabbitmq.queue_delete(self.test_queue_name) - - # initialise - method_hb = pika.spec.Basic.Deliver( - routing_key=HEARTBEAT_OUTPUT_MANAGER_ROUTING_KEY) - body = 'ping' - res = self.test_manager.rabbitmq.queue_declare( - queue=self.test_queue_name, durable=True, exclusive=False, - auto_delete=False, passive=False - ) - self.assertEqual(0, res.method.message_count) - self.test_manager.rabbitmq.queue_bind( - queue=self.test_queue_name, exchange=HEALTH_CHECK_EXCHANGE, - routing_key=HEARTBEAT_OUTPUT_MANAGER_ROUTING_KEY) - self.test_manager._process_ping(blocking_channel, method_hb, - properties, body) - # By re-declaring the queue again we can get the number of messages - # in the queue. - res = self.test_manager.rabbitmq.queue_declare( - queue=self.test_queue_name, durable=True, exclusive=False, - auto_delete=False, passive=True - ) - self.assertEqual(1, res.method.message_count) - - # Check that the message received is a valid HB - _, _, body = self.test_manager.rabbitmq.basic_get( - self.test_queue_name) - expected_output = { - 'component_name': self.test_manager.name, - 'running_processes': - [self.test_manager.parent_id_process_dict[self.parent_id_1][ - 'component_name'], - self.test_manager.parent_id_process_dict[self.parent_id_2][ - 'component_name']], - 'dead_processes': [], - 'timestamp': datetime(2012, 1, 1).timestamp(), - } - self.assertEqual(expected_output, json.loads(body)) - except Exception as e: - self.fail("Test failed: {}".format(e)) + blocking_channel = self.test_manager.rabbitmq.channel + method_chains = pika.spec.Basic.Deliver( + routing_key=self.general_routing_key) + body = json.dumps(self.config_1) + properties = pika.spec.BasicProperties() + chain_name = 'general' - @freeze_time("2012-01-01") - @mock.patch.object(SystemAlertersManager, - "_push_latest_data_to_queue_and_send") - @mock.patch.object(RabbitMQApi, "basic_ack") - @mock.patch.object(multiprocessing.Process, "is_alive") - @mock.patch.object(multiprocessing.Process, "start") - @mock.patch.object(multiprocessing.Process, "join") - @mock.patch.object(multiprocessing.Process, "terminate") - def test_process_ping_sends_a_valid_hb_if_some_processes_alive_some_dead( - self, mock_terminate, mock_join, mock_start, mock_is_alive, - mock_ack, mock_push_and_send) -> None: - # This test creates a queue which receives messages with the same - # routing key as the ones sent by send_heartbeat, and checks that the - # received heartbeat is valid. - mock_ack.return_value = None - mock_is_alive.side_effect = [True, False] - mock_start.return_value = None - mock_join.return_value = None - mock_terminate.return_value = None - mock_push_and_send.return_value = None - try: - self.test_manager._initialise_rabbitmq() - blocking_channel = self.test_manager.rabbitmq.channel - method_chains = pika.spec.Basic.Deliver( - routing_key=self.chains_routing_key) - method_general = pika.spec.Basic.Deliver( - routing_key=self.general_routing_key) - body_chain_initial = json.dumps( - self.sent_configs_example_with_default) - body_general_initial = json.dumps( - self.sent_configs_example_with_default_2) - properties = pika.spec.BasicProperties() - - # First send the new configs as the state is empty - self.test_manager._process_configs(blocking_channel, method_chains, - properties, body_chain_initial) - self.test_manager._process_configs(blocking_channel, method_general, - properties, body_general_initial) - - # Delete the queue before to avoid messages in the queue on error. - self.test_manager.rabbitmq.queue_delete(self.test_queue_name) - - # initialise - method_hb = pika.spec.Basic.Deliver( - routing_key=HEARTBEAT_OUTPUT_MANAGER_ROUTING_KEY) - body = 'ping' - res = self.test_manager.rabbitmq.queue_declare( - queue=self.test_queue_name, durable=True, exclusive=False, - auto_delete=False, passive=False - ) - self.assertEqual(0, res.method.message_count) - self.test_manager.rabbitmq.queue_bind( - queue=self.test_queue_name, exchange=HEALTH_CHECK_EXCHANGE, - routing_key=HEARTBEAT_OUTPUT_MANAGER_ROUTING_KEY) - self.test_manager._process_ping(blocking_channel, method_hb, - properties, body) + self.test_manager._process_configs(blocking_channel, method_chains, + properties, body) - # By re-declaring the queue again we can get the number of messages - # in the queue. - res = self.test_manager.rabbitmq.queue_declare( - queue=self.test_queue_name, durable=True, exclusive=False, - auto_delete=False, passive=True + expected_configs = { + chain_name: SystemAlertsConfig( + parent_id=self.parent_id_1, + open_file_descriptors=self.config_1['1'], + system_cpu_usage=self.config_1['2'], + system_storage_usage=self.config_1['3'], + system_ram_usage=self.config_1['4'], + system_is_down=self.config_1['5'], ) - self.assertEqual(1, res.method.message_count) - - # Check that the message received is a valid HB - _, _, body = self.test_manager.rabbitmq.basic_get( - self.test_queue_name) - expected_output = { - 'component_name': self.test_manager.name, - 'running_processes': - [self.test_manager.parent_id_process_dict[self.parent_id_1][ - 'component_name']], - 'dead_processes': [self.test_manager.parent_id_process_dict[ - self.parent_id_2]['component_name']], - 'timestamp': datetime(2012, 1, 1).timestamp(), - } - self.assertEqual(expected_output, json.loads(body)) - except Exception as e: - self.fail("Test failed: {}".format(e)) + } + expected_alert = ComponentResetAlert( + SYSTEM_ALERTER_NAME, datetime.now().timestamp(), + SystemAlerter.__name__, self.parent_id_1, chain_name + ) - @freeze_time("2012-01-01") + self.assertEqual(expected_configs, + self.test_manager.system_alerts_config_factory.configs) + mock_push_and_send.assert_called_once_with( + expected_alert.alert_data, SYSTEM_ALERT_ROUTING_KEY) + mock_ack.assert_called_once() + + @mock.patch.object(RabbitMQApi, 'basic_ack') @mock.patch.object(SystemAlertersManager, "_push_latest_data_to_queue_and_send") - @mock.patch.object(RabbitMQApi, "basic_ack") - @mock.patch.object(multiprocessing.Process, "is_alive") - @mock.patch.object(multiprocessing.Process, "start") - @mock.patch.object(multiprocessing.Process, "join") - @mock.patch.object(multiprocessing.Process, "terminate") - def test_process_ping_sends_a_valid_hb_if_all_processes_dead( - self, mock_terminate, mock_join, mock_start, mock_is_alive, - mock_ack, mock_push_and_send) -> None: - # This test creates a queue which receives messages with the same - # routing key as the ones sent by send_heartbeat, and checks that the - # received heartbeat is valid. + def test_process_configs_if_received_empty_configs( + self, mock_push_and_send, mock_ack) -> None: + """ + In this test we will check that if empty configs are received, the + process_configs function removes the already stored config and does not + send a reset alert. + """ mock_ack.return_value = None - mock_is_alive.side_effect = [False, False] - mock_start.return_value = None - mock_join.return_value = None - mock_terminate.return_value = None mock_push_and_send.return_value = None - try: - self.test_manager._initialise_rabbitmq() - blocking_channel = self.test_manager.rabbitmq.channel - method_chains = pika.spec.Basic.Deliver( - routing_key=self.chains_routing_key) - method_general = pika.spec.Basic.Deliver( - routing_key=self.general_routing_key) - body_chain_initial = json.dumps( - self.sent_configs_example_with_default) - body_general_initial = json.dumps( - self.sent_configs_example_with_default_2) - properties = pika.spec.BasicProperties() - - # First send the new configs as the state is empty - self.test_manager._process_configs(blocking_channel, method_chains, - properties, body_chain_initial) - self.test_manager._process_configs(blocking_channel, method_general, - properties, body_general_initial) - - # Delete the queue before to avoid messages in the queue on error. - self.test_manager.rabbitmq.queue_delete(self.test_queue_name) - - # initialise - method_hb = pika.spec.Basic.Deliver( - routing_key=HEARTBEAT_OUTPUT_MANAGER_ROUTING_KEY) - body = 'ping' - res = self.test_manager.rabbitmq.queue_declare( - queue=self.test_queue_name, durable=True, exclusive=False, - auto_delete=False, passive=False - ) - self.assertEqual(0, res.method.message_count) - self.test_manager.rabbitmq.queue_bind( - queue=self.test_queue_name, exchange=HEALTH_CHECK_EXCHANGE, - routing_key=HEARTBEAT_OUTPUT_MANAGER_ROUTING_KEY) - self.test_manager._process_ping(blocking_channel, method_hb, - properties, body) - # By re-declaring the queue again we can get the number of messages - # in the queue. - res = self.test_manager.rabbitmq.queue_declare( - queue=self.test_queue_name, durable=True, exclusive=False, - auto_delete=False, passive=True + blocking_channel = self.test_manager.rabbitmq.channel + method_chains = pika.spec.Basic.Deliver( + routing_key=self.chains_routing_key) + body = json.dumps({}) + properties = pika.spec.BasicProperties() + parsed_routing_key = self.chains_routing_key.split('.') + chain_name = parsed_routing_key[1] + ' ' + parsed_routing_key[2] + + # Store a config directly since we need to test its removal + self.test_manager.system_alerts_config_factory.add_new_config( + chain_name, self.config_1) + expected_configs = { + chain_name: SystemAlertsConfig( + parent_id=self.parent_id_1, + open_file_descriptors=self.config_1['1'], + system_cpu_usage=self.config_1['2'], + system_storage_usage=self.config_1['3'], + system_ram_usage=self.config_1['4'], + system_is_down=self.config_1['5'], ) - self.assertEqual(1, res.method.message_count) - - # Check that the message received is a valid HB - _, _, body = self.test_manager.rabbitmq.basic_get( - self.test_queue_name) - expected_output = { - 'component_name': self.test_manager.name, - 'running_processes': [], - 'dead_processes': - [self.test_manager.parent_id_process_dict[self.parent_id_1][ - 'component_name'], - self.test_manager.parent_id_process_dict[self.parent_id_2][ - 'component_name']], - 'timestamp': datetime(2012, 1, 1).timestamp(), - } - self.assertEqual(expected_output, json.loads(body)) - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @freeze_time("2012-01-01") + } + self.assertEqual(expected_configs, + self.test_manager.system_alerts_config_factory.configs) + + # Send an empty config for the same chain + self.test_manager._process_configs(blocking_channel, method_chains, + properties, body) + expected_configs = {} + self.assertEqual(expected_configs, + self.test_manager.system_alerts_config_factory.configs) + mock_push_and_send.assert_not_called() + mock_ack.assert_called_once() + + @mock.patch.object(RabbitMQApi, 'basic_ack') @mock.patch.object(SystemAlertersManager, "_push_latest_data_to_queue_and_send") - @mock.patch.object(RabbitMQApi, "basic_ack") - @mock.patch("src.alerter.alerter_starters.create_logger") - @mock.patch.object(SystemAlertersManager, "_send_heartbeat") - def test_process_ping_restarts_dead_processes( - self, send_hb_mock, mock_create_logger, mock_ack, - mock_push_and_send) -> None: - send_hb_mock.return_value = None - mock_create_logger.return_value = self.dummy_logger + def test_process_configs_if_received_empty_general_configs( + self, mock_push_and_send, mock_ack) -> None: + """ + In this test we will check that if empty general configs are + received, the process_configs function removes the already stored + config and does not send a reset alert. + """ mock_ack.return_value = None mock_push_and_send.return_value = None - try: - self.test_manager.rabbitmq.connect() - blocking_channel = self.test_manager.rabbitmq.channel - method_chains = pika.spec.Basic.Deliver( - routing_key=self.chains_routing_key) - method_general = pika.spec.Basic.Deliver( - routing_key=self.general_routing_key) - body_chain_initial = json.dumps( - self.sent_configs_example_with_default) - body_general_initial = json.dumps( - self.sent_configs_example_with_default_2) - properties = pika.spec.BasicProperties() - - # First send the new configs as the state is empty - self.test_manager._process_configs(blocking_channel, method_chains, - properties, body_chain_initial) - self.test_manager._process_configs(blocking_channel, method_general, - properties, body_general_initial) - - # Give time for the processes to start - time.sleep(1) - - # Automate the case when having all processes dead - self.test_manager.parent_id_process_dict[self.parent_id_1][ - 'process'].terminate() - self.test_manager.parent_id_process_dict[self.parent_id_1][ - 'process'].join() - self.test_manager.parent_id_process_dict[self.parent_id_2][ - 'process'].terminate() - self.test_manager.parent_id_process_dict[self.parent_id_2][ - 'process'].join() - - # Give time for the processes to terminate - time.sleep(1) - - # Check that that the processes have terminated - self.assertFalse(self.test_manager.parent_id_process_dict[ - self.parent_id_1]['process'].is_alive()) - self.assertFalse(self.test_manager.parent_id_process_dict[ - self.parent_id_2]['process'].is_alive()) - - # initialise - method_hb = pika.spec.Basic.Deliver( - routing_key=HEARTBEAT_OUTPUT_MANAGER_ROUTING_KEY) - body = 'ping' - self.test_manager._process_ping(blocking_channel, method_hb, - properties, body) - # Give time for the processes to start - time.sleep(1) - - self.assertTrue( - self.test_manager.parent_id_process_dict[self.parent_id_1][ - 'process'].is_alive()) - self.assertTrue( - self.test_manager.parent_id_process_dict[self.parent_id_2][ - 'process'].is_alive()) - - # Clean before test finishes - self.test_manager.parent_id_process_dict[self.parent_id_1][ - 'process'].terminate() - self.test_manager.parent_id_process_dict[self.parent_id_1][ - 'process'].join() - self.test_manager.parent_id_process_dict[self.parent_id_2][ - 'process'].terminate() - self.test_manager.parent_id_process_dict[self.parent_id_2][ - 'process'].join() - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch.object(SystemAlertersManager, - "_push_latest_data_to_queue_and_send") - @mock.patch.object(SystemAlertersManager, "_send_heartbeat") - @mock.patch.object(SystemAlertersManager, - "_create_and_start_alerter_process") - @mock.patch.object(multiprocessing.Process, "join") - @mock.patch.object(multiprocessing.Process, "is_alive") - def test_process_ping_restarts_dead_processes_with_correct_info( - self, mock_alive, mock_join, startup_mock, send_hb_mock, - mock_push_and_send) -> None: - - send_hb_mock.return_value = None - startup_mock.return_value = None - mock_alive.return_value = False - mock_join.return_value = None - mock_push_and_send.return_value = None - try: - self.test_manager.rabbitmq.connect() - - self.test_manager._systems_alerts_configs[self.parent_id_1] = \ - self.system_alerts_config - self.test_manager._systems_alerts_configs[self.parent_id_2] = \ - self.system_alerts_config_2 - self.test_manager._parent_id_process_dict = \ - self.config_process_dict_example - - # initialise - blocking_channel = self.test_manager.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=HEARTBEAT_OUTPUT_MANAGER_ROUTING_KEY) - properties = pika.spec.BasicProperties() - body = 'ping' - self.test_manager._process_ping(blocking_channel, method, - properties, body) - - self.assertEqual(2, startup_mock.call_count) - - call_1 = call( - self.test_manager.systems_alerts_configs[self.parent_id_1], - self.parent_id_1, self.chain_1) - call_2 = call( - self.test_manager.systems_alerts_configs[self.parent_id_2], - self.parent_id_2, self.chain_2) - startup_mock.assert_has_calls([call_1, call_2]) - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch.object(multiprocessing.Process, "is_alive") - @mock.patch.object(multiprocessing.Process, "start") - @mock.patch.object(multiprocessing, 'Process') - def test_process_ping_does_not_send_hb_if_processing_fails( - self, mock_process, mock_start, is_alive_mock) -> None: - # This test creates a queue which receives messages with the same - # routing key as the ones sent by send_heartbeat. In this test we will - # check that no heartbeat is sent when mocking a raised exception. - is_alive_mock.side_effect = self.test_exception - mock_start.return_value = None - mock_process.side_effect = self.dummy_process1 - try: - self.test_manager._initialise_rabbitmq() - - # Delete the queue before to avoid messages in the queue on error. - self.test_manager.rabbitmq.queue_delete(self.test_queue_name) - - self.test_manager._systems_alerts_configs[self.parent_id_1] = \ - self.system_alerts_config - self.test_manager._systems_alerts_configs[self.parent_id_2] = \ - self.system_alerts_config_2 - self.test_manager._parent_id_process_dict = \ - self.config_process_dict_example - - # initialise - blocking_channel = self.test_manager.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=HEARTBEAT_OUTPUT_MANAGER_ROUTING_KEY) - properties = pika.spec.BasicProperties() - body = 'ping' - res = self.test_manager.rabbitmq.queue_declare( - queue=self.test_queue_name, durable=True, exclusive=False, - auto_delete=False, passive=False - ) - self.assertEqual(0, res.method.message_count) - self.test_manager.rabbitmq.queue_bind( - queue=self.test_queue_name, exchange=HEALTH_CHECK_EXCHANGE, - routing_key=HEARTBEAT_OUTPUT_MANAGER_ROUTING_KEY) - self.test_manager._process_ping(blocking_channel, method, - properties, body) - - # By re-declaring the queue again we can get the number of messages - # in the queue. - res = self.test_manager.rabbitmq.queue_declare( - queue=self.test_queue_name, durable=True, exclusive=False, - auto_delete=False, passive=True + blocking_channel = self.test_manager.rabbitmq.channel + method_chains = pika.spec.Basic.Deliver( + routing_key=self.general_routing_key) + body = json.dumps({}) + properties = pika.spec.BasicProperties() + chain_name = 'general' + + # Store a config directly since we need to test its removal + self.test_manager.system_alerts_config_factory.add_new_config( + chain_name, self.config_1) + expected_configs = { + chain_name: SystemAlertsConfig( + parent_id=self.parent_id_1, + open_file_descriptors=self.config_1['1'], + system_cpu_usage=self.config_1['2'], + system_storage_usage=self.config_1['3'], + system_ram_usage=self.config_1['4'], + system_is_down=self.config_1['5'], ) - self.assertEqual(0, res.method.message_count) - except Exception as e: - self.fail("Test failed: {}".format(e)) - - def test_proc_ping_send_hb_does_not_raise_msg_not_del_exce_if_hb_not_routed( - self) -> None: - try: - self.test_manager._initialise_rabbitmq() - - # initialise - blocking_channel = self.test_manager.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=HEARTBEAT_OUTPUT_MANAGER_ROUTING_KEY) - properties = pika.spec.BasicProperties() - body = 'ping' - - self.test_manager._process_ping(blocking_channel, method, - properties, body) - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch.object(SystemAlertersManager, "_send_heartbeat") - def test_process_ping_send_hb_raises_amqp_connection_err_on_connection_err( - self, hb_mock) -> None: - hb_mock.side_effect = pika.exceptions.AMQPConnectionError('test') - try: - self.test_manager._initialise_rabbitmq() - - # initialise - blocking_channel = self.test_manager.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=HEARTBEAT_OUTPUT_MANAGER_ROUTING_KEY) - properties = pika.spec.BasicProperties() - body = 'ping' - - self.assertRaises(pika.exceptions.AMQPConnectionError, - self.test_manager._process_ping, blocking_channel, - method, properties, body) - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch.object(SystemAlertersManager, "_send_heartbeat") - def test_process_ping_send_hb_raises_amqp_chan_err_on_chan_err( - self, hb_mock) -> None: - hb_mock.side_effect = pika.exceptions.AMQPChannelError('test') - try: - self.test_manager._initialise_rabbitmq() - - # initialise - blocking_channel = self.test_manager.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=HEARTBEAT_OUTPUT_MANAGER_ROUTING_KEY) - properties = pika.spec.BasicProperties() - body = 'ping' - - self.assertRaises(pika.exceptions.AMQPChannelError, - self.test_manager._process_ping, blocking_channel, - method, properties, body) - except Exception as e: - self.fail("Test failed: {}".format(e)) - - @mock.patch.object(SystemAlertersManager, "_send_heartbeat") - def test_process_ping_send_hb_raises_exception_on_unexpected_exception( - self, hb_mock) -> None: - hb_mock.side_effect = self.test_exception - try: - self.test_manager._initialise_rabbitmq() - - # initialise - blocking_channel = self.test_manager.rabbitmq.channel - method = pika.spec.Basic.Deliver( - routing_key=HEARTBEAT_OUTPUT_MANAGER_ROUTING_KEY) - properties = pika.spec.BasicProperties() - body = 'ping' - - self.assertRaises(PANICException, self.test_manager._process_ping, - blocking_channel, method, properties, body) - except Exception as e: - self.fail("Test failed: {}".format(e)) + } + self.assertEqual(expected_configs, + self.test_manager.system_alerts_config_factory.configs) + + # Send an empty config for the same chain + self.test_manager._process_configs(blocking_channel, method_chains, + properties, body) + expected_configs = {} + self.assertEqual(expected_configs, + self.test_manager.system_alerts_config_factory.configs) + mock_push_and_send.assert_not_called() + mock_ack.assert_called_once() + + @mock.patch.object(QueuingPublisherSubscriberComponent, "_push_to_queue") + @mock.patch.object(SystemAlertersManager, "_send_data") + def test_push_latest_data_to_queue_and_send_pushes_correctly_and_sends( + self, mock_send_data, mock_push) -> None: + mock_send_data.return_value = None + mock_push.return_value = None + test_dict = {'test_key': 'test_val'} + + self.test_manager._push_latest_data_to_queue_and_send( + test_dict, SYSTEM_ALERT_ROUTING_KEY) + + mock_push.assert_called_once_with( + data=test_dict, exchange=ALERT_EXCHANGE, + routing_key=SYSTEM_ALERT_ROUTING_KEY, + properties=pika.BasicProperties(delivery_mode=2), mandatory=True + ) + mock_send_data.assert_called_once() diff --git a/alerter/test/alerter/test_starters.py b/alerter/test/alerter/test_starters.py index 917ad56b2..7fbb0b4b2 100644 --- a/alerter/test/alerter/test_starters.py +++ b/alerter/test/alerter/test_starters.py @@ -21,16 +21,16 @@ from src.alerter.alerters.node.cosmos import CosmosNodeAlerter from src.alerter.alerters.node.evm import EVMNodeAlerter from src.alerter.alerters.system import SystemAlerter -from src.configs.alerts.system import SystemAlertsConfig from src.configs.factory.alerts.chainlink_alerts import ( ChainlinkNodeAlertsConfigsFactory, ChainlinkContractAlertsConfigsFactory) from src.configs.factory.alerts.cosmos_alerts import ( CosmosNodeAlertsConfigsFactory, CosmosNetworkAlertsConfigsFactory) from src.configs.factory.alerts.evm_alerts import EVMNodeAlertsConfigsFactory +from src.configs.factory.alerts.system_alerts import SystemAlertsConfigsFactory from src.message_broker.rabbitmq import RabbitMQApi from src.utils import env from src.utils.constants.names import ( - SYSTEM_ALERTER_NAME_TEMPLATE, CHAINLINK_NODE_ALERTER_NAME, + SYSTEM_ALERTER_NAME, CHAINLINK_NODE_ALERTER_NAME, CHAINLINK_CONTRACT_ALERTER_NAME, EVM_NODE_ALERTER_NAME, COSMOS_NODE_ALERTER_NAME, COSMOS_NETWORK_ALERTER_NAME) @@ -92,19 +92,12 @@ def setUp(self) -> None: # Similarly for Dockerhub self.dockerhub_alerter_name = "DockerHub Alerter" - self.system_alerts_config = SystemAlertsConfig( - self.parent_id, - self.open_file_descriptors, - self.system_cpu_usage, - self.system_storage_usage, - self.system_ram_usage, - self.system_is_down - ) + self.system_alerts_configs_factory = SystemAlertsConfigsFactory() self.test_system_alerter = SystemAlerter( self.alerter_name, - self.system_alerts_config, self.dummy_logger, + self.system_alerts_configs_factory, self.rabbitmq, env.ALERTER_PUBLISHING_QUEUE_SIZE ) @@ -173,7 +166,7 @@ def tearDown(self) -> None: self.test_github_alerter = None self.test_dockerhub_alerter = None self.rabbitmq = None - self.system_alerts_config = None + self.system_alerts_configs_factory = None self.test_system_alerter = None self.evm_node_alerts_configs_factory = None self.chainlink_node_alerts_configs_factory = None @@ -191,13 +184,10 @@ def test_initialise_alerter_logger_calls_create_logger_correctly( self, mock_create_logger) -> None: mock_create_logger.return_value = None - _initialise_alerter_logger( - SYSTEM_ALERTER_NAME_TEMPLATE.format(self.chain_name), - self.alerter_name) + _initialise_alerter_logger(SYSTEM_ALERTER_NAME, self.alerter_name) mock_create_logger.assert_called_once_with( - env.ALERTERS_LOG_FILE_TEMPLATE.format( - SYSTEM_ALERTER_NAME_TEMPLATE.format(self.chain_name)), + env.ALERTERS_LOG_FILE_TEMPLATE.format(SYSTEM_ALERTER_NAME), self.alerter_name, env.LOGGING_LEVEL, rotating=True ) @@ -206,9 +196,8 @@ def test_initialise_alerter_logger_returns_created_logger_if_init_correct( self, mock_create_logger) -> None: mock_create_logger.return_value = self.dummy_logger - actual_output = _initialise_alerter_logger( - SYSTEM_ALERTER_NAME_TEMPLATE.format(self.chain_name), - self.alerter_name) + actual_output = _initialise_alerter_logger(SYSTEM_ALERTER_NAME, + self.alerter_name) self.assertEqual(self.dummy_logger, actual_output) @@ -217,13 +206,10 @@ def test_initialise_system_alerter_calls_initialise_logger_correctly( self, mock_init_logger) -> None: mock_init_logger.return_value = self.dummy_logger - _initialise_system_alerter(self.system_alerts_config, - self.parent_id) + _initialise_system_alerter(self.system_alerts_configs_factory) - mock_init_logger.assert_called_once_with( - SYSTEM_ALERTER_NAME_TEMPLATE.format(self.parent_id), - SystemAlerter.__name__ - ) + mock_init_logger.assert_called_once_with(SYSTEM_ALERTER_NAME, + SystemAlerter.__name__) @mock.patch("src.alerter.alerter_starters._initialise_alerter_logger") def test_initialise_github_alerter_calls_initialise_logger_correctly( @@ -318,14 +304,12 @@ def test_initialise_system_alerter_creates_system_alerter_correctly( mock_init_logger.return_value = self.dummy_logger mock_system_alerter.__name__ = "system_alerter_name" - _initialise_system_alerter(self.system_alerts_config, - self.parent_id) + _initialise_system_alerter(self.system_alerts_configs_factory) args, _ = mock_system_alerter.call_args - self.assertEqual(SYSTEM_ALERTER_NAME_TEMPLATE.format(self.parent_id), - args[0]) - self.assertEqual(self.system_alerts_config, args[1]) - self.assertEqual(self.dummy_logger, args[2]) + self.assertEqual(SYSTEM_ALERTER_NAME, args[0]) + self.assertEqual(self.dummy_logger, args[1]) + self.assertEqual(self.system_alerts_configs_factory, args[2]) self.assertEqual(type(self.rabbitmq), type(args[3])) self.assertEqual(env.ALERTER_PUBLISHING_QUEUE_SIZE, args[4]) @@ -451,14 +435,13 @@ def test_start_system_alerter_calls_sub_functions_correctly( mock_start_alerter.return_value = None mock_initialise_alerter.return_value = self.test_system_alerter - start_system_alerter(self.system_alerts_config, - self.parent_id) + start_system_alerter(self.system_alerts_configs_factory) mock_start_alerter.assert_called_once_with( self.test_system_alerter ) mock_initialise_alerter.assert_called_once_with( - self.system_alerts_config, self.parent_id + self.system_alerts_configs_factory ) @mock.patch("src.alerter.alerter_starters._initialise_github_alerter") diff --git a/alerter/test/configs/factory/alerts/test_chainlink_alerts.py b/alerter/test/configs/factory/alerts/test_chainlink_alerts.py index 4788f52b5..8681c03bb 100644 --- a/alerter/test/configs/factory/alerts/test_chainlink_alerts.py +++ b/alerter/test/configs/factory/alerts/test_chainlink_alerts.py @@ -33,9 +33,9 @@ def setUp(self) -> None: chainlink_node_config_metrics = [ 'head_tracker_current_head', 'head_tracker_heads_received_total', - 'tx_manager_gas_bump_exceeds_limit_total', 'eth_balance_amount', + 'tx_manager_gas_bump_exceeds_limit_total', 'balance_amount', 'unconfirmed_transactions', 'run_status_update_total', - 'max_unconfirmed_blocks', 'eth_balance_amount_increase', + 'max_unconfirmed_blocks', 'balance_amount_increase', 'process_start_time_seconds', 'node_is_down' ] chainlink_contracts_config_metrics = [ @@ -103,9 +103,9 @@ def setUp(self) -> None: 'unconfirmed_transactions'], run_status_update_total=filtered_1_cl_node[ 'run_status_update_total'], - eth_balance_amount=filtered_1_cl_node['eth_balance_amount'], - eth_balance_amount_increase=filtered_1_cl_node[ - 'eth_balance_amount_increase'], + balance_amount=filtered_1_cl_node['balance_amount'], + balance_amount_increase=filtered_1_cl_node[ + 'balance_amount_increase'], node_is_down=filtered_1_cl_node['node_is_down'] ) self.alerts_config_2_cl_node = ChainlinkNodeAlertsConfig( @@ -124,9 +124,9 @@ def setUp(self) -> None: 'unconfirmed_transactions'], run_status_update_total=filtered_2_cl_node[ 'run_status_update_total'], - eth_balance_amount=filtered_2_cl_node['eth_balance_amount'], - eth_balance_amount_increase=filtered_2_cl_node[ - 'eth_balance_amount_increase'], + balance_amount=filtered_2_cl_node['balance_amount'], + balance_amount_increase=filtered_2_cl_node[ + 'balance_amount_increase'], node_is_down=filtered_2_cl_node['node_is_down'] ) self.alerts_config_1_cl_contract = ChainlinkContractAlertsConfig( diff --git a/alerter/test/configs/factory/alerts/test_system_alerts.py b/alerter/test/configs/factory/alerts/test_system_alerts.py new file mode 100644 index 000000000..126867b81 --- /dev/null +++ b/alerter/test/configs/factory/alerts/test_system_alerts.py @@ -0,0 +1,305 @@ +import copy +import unittest + +from parameterized import parameterized + +from src.configs.alerts.system import SystemAlertsConfig +from src.configs.factory.alerts.system_alerts import SystemAlertsConfigsFactory +from src.utils.exceptions import ParentIdsMissMatchInAlertsConfiguration + + +class TestSystemAlertsConfigsFactory(unittest.TestCase): + """ + Although currently there is only one type of system alerts config, the tests + were conducted using parameterize.expand, just in case in the future we + add more config types. + """ + + def setUp(self) -> None: + # Some dummy values + self.test_parent_id_1 = 'chain_name_d60b8a8e-9c70-4601-9103' + self.test_parent_id_2 = 'chain_name_dbfsdg7s-sdff-4644-7456' + self.test_chain_name_1 = 'general' + self.test_chain_name_2 = 'cosmos cosmoshub' + + """ + First we will construct the received alerts configurations. + """ + + system_config_metrics = [ + 'open_file_descriptors', 'system_cpu_usage', + 'system_storage_usage', 'system_ram_usage', 'system_is_down' + ] + self.received_config_example_1_system = {} + self.received_config_example_2_system = {} + + for i in range(len(system_config_metrics)): + self.received_config_example_1_system[str(i)] = { + 'name': system_config_metrics[i], + 'parent_id': self.test_parent_id_1 + } + self.received_config_example_2_system[str(i)] = { + 'name': system_config_metrics[i], + 'parent_id': self.test_parent_id_2 + } + + """ + Now we will construct the expected config objects + """ + + filtered_1_system = {} + for _, config in self.received_config_example_1_system.items(): + filtered_1_system[config['name']] = copy.deepcopy(config) + + filtered_2_system = {} + for _, config in self.received_config_example_2_system.items(): + filtered_2_system[config['name']] = copy.deepcopy(config) + + self.alerts_config_1_system = SystemAlertsConfig( + parent_id=self.test_parent_id_1, + open_file_descriptors=filtered_1_system['open_file_descriptors'], + system_cpu_usage=filtered_1_system['system_cpu_usage'], + system_storage_usage=filtered_1_system['system_storage_usage'], + system_ram_usage=filtered_1_system['system_ram_usage'], + system_is_down=filtered_1_system['system_is_down'] + ) + self.alerts_config_2_system = SystemAlertsConfig( + parent_id=self.test_parent_id_2, + open_file_descriptors=filtered_2_system['open_file_descriptors'], + system_cpu_usage=filtered_2_system['system_cpu_usage'], + system_storage_usage=filtered_2_system['system_storage_usage'], + system_ram_usage=filtered_2_system['system_ram_usage'], + system_is_down=filtered_2_system['system_is_down'] + ) + + self.system_configs_factory = SystemAlertsConfigsFactory() + + def tearDown(self) -> None: + self.received_config_example_1_system = None + self.received_config_example_2_system = None + self.alerts_config_1_system = None + self.alerts_config_2_system = None + self.system_configs_factory = None + + @parameterized.expand([ + ('self.system_configs_factory', + 'self.received_config_example_1_system', + 'self.alerts_config_1_system', + 'self.received_config_example_2_system', + 'self.alerts_config_2_system',) + ]) + def test_add_new_config_adds_a_new_config( + self, configs_factory, received_config_1, alerts_config_1, + received_config_2, alerts_config_2) -> None: + """ + In this test we will check that add_new_config adds the newly received + config correctly in the state. First we will test for when the state is + empty and then for when the state is non-empty. + """ + configs_factory = eval(configs_factory) + received_config_1 = eval(received_config_1) + alerts_config_1 = eval(alerts_config_1) + received_config_2 = eval(received_config_2) + alerts_config_2 = eval(alerts_config_2) + + # First check that the state is empty + self.assertEqual({}, configs_factory.configs) + + # Add a config and check that the state was modified correctly + configs_factory.add_new_config(self.test_chain_name_1, + received_config_1) + expected_state = { + self.test_chain_name_1: alerts_config_1 + } + self.assertEqual(expected_state, configs_factory.configs) + + # Add another config and check that the state was modified correctly + configs_factory.add_new_config(self.test_chain_name_2, + received_config_2) + expected_state = { + self.test_chain_name_1: alerts_config_1, + self.test_chain_name_2: alerts_config_2 + } + self.assertEqual(expected_state, configs_factory.configs) + + @parameterized.expand([ + ('self.system_configs_factory', + 'self.received_config_example_1_system',) + ]) + def test_add_new_config_raises_ParentIdsMissMatch_if_parent_ids_not_equal( + self, configs_factory, received_config) -> None: + """ + In this test we will check that the specified exception is raised and + that the state is not modified + """ + configs_factory = eval(configs_factory) + received_config = eval(received_config) + + received_config['1']['parent_id'] = 'bad_parent_id' + old_state = copy.deepcopy(configs_factory.configs) + + self.assertRaises( + ParentIdsMissMatchInAlertsConfiguration, + configs_factory.add_new_config, self.test_chain_name_1, + received_config) + self.assertEqual(old_state, configs_factory.configs) + + @parameterized.expand([ + ('self.system_configs_factory', 'self.alerts_config_1_system', + 'self.alerts_config_2_system',) + ]) + def test_remove_config_removes_config_for_chain_if_chain_exists( + self, configs_factory, alerts_config_1, alerts_config_2) -> None: + configs_factory = eval(configs_factory) + alerts_config_1 = eval(alerts_config_1) + alerts_config_2 = eval(alerts_config_2) + + state = { + self.test_chain_name_1: alerts_config_1, + self.test_chain_name_2: alerts_config_2 + } + configs_factory._configs = state + + configs_factory.remove_config(self.test_chain_name_1) + expected_state = { + self.test_chain_name_2: alerts_config_2 + } + self.assertEqual(expected_state, configs_factory.configs) + + @parameterized.expand([ + ('self.system_configs_factory', 'self.alerts_config_1_system', + 'self.alerts_config_2_system',) + ]) + def test_remove_config_does_nothing_if_no_config_exists_for_chain( + self, configs_factory, alerts_config_1, alerts_config_2) -> None: + """ + We will check that the state is kept intact if a configuration does not + exist for a chain + """ + configs_factory = eval(configs_factory) + alerts_config_1 = eval(alerts_config_1) + alerts_config_2 = eval(alerts_config_2) + + state = { + self.test_chain_name_1: alerts_config_1, + self.test_chain_name_2: alerts_config_2 + } + configs_factory._configs = state + + configs_factory.remove_config('bad_chain') + self.assertEqual(state, configs_factory.configs) + + @parameterized.expand([ + ('self.system_configs_factory', 'self.alerts_config_1_system', + 'self.alerts_config_2_system',) + ]) + def test_config_exists_returns_true_if_config_exists( + self, configs_factory, alerts_config_1, alerts_config_2) -> None: + configs_factory = eval(configs_factory) + alerts_config_1 = eval(alerts_config_1) + alerts_config_2 = eval(alerts_config_2) + + state = { + self.test_chain_name_1: alerts_config_1, + self.test_chain_name_2: alerts_config_2 + } + configs_factory._configs = state + self.assertTrue(configs_factory.config_exists(self.test_chain_name_1)) + + @parameterized.expand([ + ('self.system_configs_factory', 'self.alerts_config_1_system',) + ]) + def test_config_exists_returns_false_if_config_does_not_exists( + self, configs_factory, alerts_config_1) -> None: + """ + We will perform this test for both when the expected config object is + invalid and for when the chain_name does not exist in the state + """ + configs_factory = eval(configs_factory) + alerts_config_1 = eval(alerts_config_1) + + state = { + self.test_chain_name_1: alerts_config_1, + self.test_chain_name_2: 'bad_object' + } + configs_factory._configs = state + self.assertFalse(configs_factory.config_exists('bad_chain')) + self.assertFalse(configs_factory.config_exists(self.test_chain_name_2)) + + @parameterized.expand([ + ('self.system_configs_factory', 'self.alerts_config_1_system', + 'self.alerts_config_2_system',) + ]) + def test_get_parent_id_gets_id_from_stored_config_if_chain_exists_in_state( + self, configs_factory, alerts_config_1, alerts_config_2) -> None: + configs_factory = eval(configs_factory) + alerts_config_1 = eval(alerts_config_1) + alerts_config_2 = eval(alerts_config_2) + + state = { + self.test_chain_name_1: alerts_config_1, + self.test_chain_name_2: alerts_config_2 + } + configs_factory._configs = state + + actual_output = configs_factory.get_parent_id(self.test_chain_name_1) + self.assertEqual(self.test_parent_id_1, actual_output) + + @parameterized.expand([ + ('self.system_configs_factory', 'self.alerts_config_1_system',) + ]) + def test_get_parent_id_returns_none_if_chain_does_not_exist_in_state( + self, configs_factory, alerts_config_1) -> None: + """ + We will perform this test for both when the expected config object is + invalid and for when the chain_name does not exist in the state + """ + configs_factory = eval(configs_factory) + alerts_config_1 = eval(alerts_config_1) + + state = { + self.test_chain_name_1: alerts_config_1, + self.test_chain_name_2: 'bad_object' + } + configs_factory._configs = state + self.assertIsNone(configs_factory.get_parent_id(self.test_chain_name_2)) + self.assertIsNone(configs_factory.get_parent_id('bad_chain')) + + @parameterized.expand([ + ('self.system_configs_factory', 'self.alerts_config_1_system', + 'self.alerts_config_2_system',) + ]) + def test_get_chain_name_gets_name_given_the_parent_id_if_config_exists( + self, configs_factory, alerts_config_1, alerts_config_2) -> None: + configs_factory = eval(configs_factory) + alerts_config_1 = eval(alerts_config_1) + alerts_config_2 = eval(alerts_config_2) + + state = { + self.test_chain_name_1: alerts_config_1, + self.test_chain_name_2: alerts_config_2 + } + configs_factory._configs = state + + actual_output = configs_factory.get_chain_name(self.test_parent_id_1) + self.assertEqual(self.test_chain_name_1, actual_output) + + @parameterized.expand([ + ('self.system_configs_factory', 'self.alerts_config_1_system',) + ]) + def test_get_chain_name_returns_none_if_no_config_exists_for_parent_id( + self, configs_factory, alerts_config_1) -> None: + """ + We will perform this test for both when the expected config object is + invalid and for when no config is associated with the given parent_id + """ + configs_factory = eval(configs_factory) + alerts_config_1 = eval(alerts_config_1) + + state = { + self.test_chain_name_1: alerts_config_1, + self.test_chain_name_2: 'bad_object' + } + configs_factory._configs = state + self.assertIsNone(configs_factory.get_chain_name(self.test_parent_id_2)) + self.assertIsNone(configs_factory.get_chain_name('bad_id')) diff --git a/alerter/test/data_store/stores/node/test_chainlink.py b/alerter/test/data_store/stores/node/test_chainlink.py index f965a3cb1..5a7908a9d 100644 --- a/alerter/test/data_store/stores/node/test_chainlink.py +++ b/alerter/test/data_store/stores/node/test_chainlink.py @@ -91,7 +91,7 @@ def setUp(self) -> None: 'percentile': 50.5, 'price': 22.0, } - self.test_eth_balance_info = { + self.test_balance_info = { 'address': 'address1', 'balance': 34.4, 'latest_usage': 5.0, } self.test_last_prometheus_source_used = "prometheus_source_1" @@ -124,7 +124,7 @@ def setUp(self) -> None: self.test_total_errored_job_runs, "current_gas_price_info": self.test_current_gas_price_info, - "eth_balance_info": self.test_eth_balance_info, + "balance_info": self.test_balance_info, } } } @@ -167,11 +167,11 @@ def setUp(self) -> None: 'price': self.test_current_gas_price_info[ 'price'] + self.pad, }, - "eth_balance_info": { + "balance_info": { 'address': 'address1', - 'balance': self.test_eth_balance_info[ - 'balance'] + self.pad, - 'latest_usage': self.test_eth_balance_info[ + 'balance': self.test_balance_info['balance'] + + self.pad, + 'latest_usage': self.test_balance_info[ 'latest_usage'] + self.pad }, } @@ -544,10 +544,10 @@ def test_process_redis_prometheus_result_store_stores_correctly( Keys.get_cl_node_total_errored_job_runs(self.node_id) ).decode("utf-8"), 'bad_val')) self.assertEqual( - data['data']['eth_balance_info'], + data['data']['balance_info'], json.loads(self.redis.hget( redis_hash, - Keys.get_cl_node_eth_balance_info(self.node_id) + Keys.get_cl_node_balance_info(self.node_id) ).decode("utf-8"))) self.assertEqual( data['meta_data']['last_source_used'], @@ -624,7 +624,7 @@ def test_process_redis_prometheus_error_store_stores_correctly_if_down_err( ) self.assertEqual( None, self.redis.hget(redis_hash, - Keys.get_cl_node_eth_balance_info( + Keys.get_cl_node_balance_info( self.node_id)) ) self.assertEqual( @@ -695,7 +695,7 @@ def test_process_redis_prometheus_error_store_stores_correctly_not_down_err( ) self.assertEqual( None, self.redis.hget(redis_hash, - Keys.get_cl_node_eth_balance_info( + Keys.get_cl_node_balance_info( self.node_id)) ) self.assertEqual( @@ -762,7 +762,7 @@ def test_process_mongo_prometheus_result_store_stores_correctly( metrics['no_of_unconfirmed_txs'], metrics['total_errored_job_runs'], metrics['current_gas_price_info'], - metrics['eth_balance_info'], + metrics['balance_info'], metrics['went_down_at'], meta_data['last_source_used'], meta_data['last_monitored'], @@ -787,7 +787,7 @@ def test_process_mongo_prometheus_result_store_stores_correctly( 'bad_val'), None if document[node_id][0]['current_gas_price_info'] == 'None' else json.loads(document[node_id][0]['current_gas_price_info']), - json.loads(document[node_id][0]['eth_balance_info']), + json.loads(document[node_id][0]['balance_info']), None if document[node_id][0]['went_down_at_prometheus'] == 'None' else convert_to_float( document[node_id][0]['went_down_at_prometheus'], 'bad_val'), @@ -826,7 +826,7 @@ def test_process_mongo_prometheus_result_store_stores_correctly( metrics['no_of_unconfirmed_txs'], metrics['total_errored_job_runs'], metrics['current_gas_price_info'], - metrics['eth_balance_info'], + metrics['balance_info'], metrics['went_down_at'], meta_data['last_source_used'], meta_data['last_monitored'], @@ -851,7 +851,7 @@ def test_process_mongo_prometheus_result_store_stores_correctly( 'bad_val'), None if document[node_id][0]['current_gas_price_info'] == 'None' else json.loads(document[node_id][0]['current_gas_price_info']), - json.loads(document[node_id][0]['eth_balance_info']), + json.loads(document[node_id][0]['balance_info']), None if document[node_id][0]['went_down_at_prometheus'] == 'None' else convert_to_float( document[node_id][0]['went_down_at_prometheus'], 'bad_val'), diff --git a/alerter/test/data_store/stores/test_system.py b/alerter/test/data_store/stores/test_system.py index b30d55452..ae4232709 100644 --- a/alerter/test/data_store/stores/test_system.py +++ b/alerter/test/data_store/stores/test_system.py @@ -18,10 +18,9 @@ from src.data_store.stores.system import SystemStore from src.message_broker.rabbitmq import RabbitMQApi from src.utils import env -from src.utils.constants.rabbitmq import (STORE_EXCHANGE, HEALTH_CHECK_EXCHANGE, - SYSTEM_STORE_INPUT_QUEUE_NAME, - HEARTBEAT_OUTPUT_WORKER_ROUTING_KEY, - SYSTEM_STORE_INPUT_ROUTING_KEY, TOPIC) +from src.utils.constants.rabbitmq import ( + STORE_EXCHANGE, HEALTH_CHECK_EXCHANGE, SYSTEM_STORE_INPUT_QUEUE_NAME, TOPIC, + HEARTBEAT_OUTPUT_WORKER_ROUTING_KEY, SYSTEM_TRANSFORMED_DATA_ROUTING_KEY) from src.utils.exceptions import (PANICException, ReceivedUnexpectedDataException) from test.test_utils.utils import ( @@ -67,7 +66,7 @@ def setUp(self) -> None: self.rabbitmq) self.heartbeat_routing_key = HEARTBEAT_OUTPUT_WORKER_ROUTING_KEY - self._input_routing_key = 'transformed_data.system.test_system' + self._input_routing_key = SYSTEM_TRANSFORMED_DATA_ROUTING_KEY self.test_queue_name = 'test queue' connect_to_rabbit(self.rabbitmq) @@ -78,7 +77,7 @@ def setUp(self) -> None: self.rabbitmq.queue_declare(SYSTEM_STORE_INPUT_QUEUE_NAME, False, True, False, False) self.rabbitmq.queue_bind(SYSTEM_STORE_INPUT_QUEUE_NAME, STORE_EXCHANGE, - SYSTEM_STORE_INPUT_ROUTING_KEY) + SYSTEM_TRANSFORMED_DATA_ROUTING_KEY) connect_to_rabbit(self.test_rabbit_manager) self.test_rabbit_manager.queue_declare(self.test_queue_name, False, diff --git a/alerter/test/data_transformers/node/test_chainlink.py b/alerter/test/data_transformers/node/test_chainlink.py index 444b1032b..afe8faf67 100644 --- a/alerter/test/data_transformers/node/test_chainlink.py +++ b/alerter/test/data_transformers/node/test_chainlink.py @@ -91,8 +91,9 @@ def setUp(self) -> None: 'percentile': 50.5, 'price': 22.0, } - self.test_eth_balance_info = { + self.test_balance_info = { 'address': 'address1', 'balance': 34.4, 'latest_usage': 5.0, + 'symbol': 'TEST' } self.test_last_prometheus_source_used = "prometheus_source_1" self.test_last_monitored_prometheus = 45.666786 @@ -115,8 +116,8 @@ def setUp(self) -> None: self.test_chainlink_node.set_current_gas_price_info( self.test_current_gas_price_info['percentile'], self.test_current_gas_price_info['price']) - self.test_chainlink_node.set_eth_balance_info( - self.test_eth_balance_info) + self.test_chainlink_node.set_balance_info( + self.test_balance_info) self.test_chainlink_node.set_last_prometheus_source_used( self.test_last_prometheus_source_used) self.test_chainlink_node.set_last_monitored_prometheus( @@ -139,8 +140,9 @@ def setUp(self) -> None: 'percentile': 52.5, 'price': 24.0, } - self.test_eth_balance_info_new = { + self.test_balance_info_new = { 'address': 'address1', 'balance': 44.4, 'latest_usage': 0.0, + 'symbol': 'TEST' } self.test_last_prometheus_source_used_new = "prometheus_source_2" self.test_last_monitored_prometheus_new = 47.666786 @@ -165,8 +167,8 @@ def setUp(self) -> None: self.test_chainlink_node_new.set_current_gas_price_info( self.test_current_gas_price_info_new['percentile'], self.test_current_gas_price_info_new['price']) - self.test_chainlink_node_new.set_eth_balance_info( - self.test_eth_balance_info_new) + self.test_chainlink_node_new.set_balance_info( + self.test_balance_info_new) self.test_chainlink_node_new.set_last_prometheus_source_used( self.test_last_prometheus_source_used_new) self.test_chainlink_node_new.set_last_monitored_prometheus( @@ -200,8 +202,8 @@ def setUp(self) -> None: self.loaded_cl_node_trans_data.set_current_gas_price_info( self.test_current_gas_price_info['percentile'], self.test_current_gas_price_info['price']) - self.loaded_cl_node_trans_data.set_eth_balance_info( - self.test_eth_balance_info) + self.loaded_cl_node_trans_data.set_balance_info( + self.test_balance_info) self.loaded_cl_node_trans_data.set_last_prometheus_source_used( self.test_last_prometheus_source_used) self.loaded_cl_node_trans_data.set_last_monitored_prometheus( @@ -246,10 +248,10 @@ def setUp(self) -> None: self.test_current_gas_price_info_new[ 'price'] }, - 'eth_balance': { + 'balance': { 'address': 'address1', - 'balance': self.test_eth_balance_info_new[ - 'balance'], + 'balance': self.test_balance_info_new['balance'], + 'symbol': self.test_balance_info_new['symbol'] }, }, } @@ -327,7 +329,7 @@ def setUp(self) -> None: self.test_total_errored_job_runs_new, 'current_gas_price_info': self.test_current_gas_price_info_new, - 'eth_balance_info': self.test_eth_balance_info_new, + 'balance_info': self.test_balance_info_new, }, } } @@ -433,9 +435,9 @@ def setUp(self) -> None: 'current': self.test_current_gas_price_info_new, 'previous': self.test_current_gas_price_info }, - 'eth_balance_info': { - 'current': self.test_eth_balance_info_new, - 'previous': self.test_eth_balance_info + 'balance_info': { + 'current': self.test_balance_info_new, + 'previous': self.test_balance_info }, }, } diff --git a/alerter/test/data_transformers/test_system.py b/alerter/test/data_transformers/test_system.py index ef40412b2..c083e0cab 100644 --- a/alerter/test/data_transformers/test_system.py +++ b/alerter/test/data_transformers/test_system.py @@ -21,7 +21,7 @@ from src.utils.constants.rabbitmq import ( HEALTH_CHECK_EXCHANGE, RAW_DATA_EXCHANGE, STORE_EXCHANGE, ALERT_EXCHANGE, SYSTEM_DT_INPUT_QUEUE_NAME, SYSTEM_RAW_DATA_ROUTING_KEY, - SYSTEM_TRANSFORMED_DATA_ROUTING_KEY_TEMPLATE, + SYSTEM_TRANSFORMED_DATA_ROUTING_KEY, HEARTBEAT_OUTPUT_WORKER_ROUTING_KEY, TOPIC) from src.utils.exceptions import (PANICException, SystemIsDownException, ReceivedUnexpectedDataException, @@ -966,16 +966,14 @@ def test_place_latest_data_on_queue_places_the_correct_data_on_queue( ) expected_data_for_alerting = { 'exchange': ALERT_EXCHANGE, - 'routing_key': SYSTEM_TRANSFORMED_DATA_ROUTING_KEY_TEMPLATE.format( - self.test_system_parent_id), + 'routing_key': SYSTEM_TRANSFORMED_DATA_ROUTING_KEY, 'data': eval(data_for_alerting), 'properties': pika.BasicProperties(delivery_mode=2), 'mandatory': True } expected_data_for_saving = { 'exchange': STORE_EXCHANGE, - 'routing_key': SYSTEM_TRANSFORMED_DATA_ROUTING_KEY_TEMPLATE.format( - self.test_system_parent_id), + 'routing_key': SYSTEM_TRANSFORMED_DATA_ROUTING_KEY, 'data': eval(data_for_saving), 'properties': pika.BasicProperties(delivery_mode=2), 'mandatory': True @@ -989,18 +987,6 @@ def test_place_latest_data_on_queue_places_the_correct_data_on_queue( expected_data_for_saving, self.test_data_transformer.publishing_queue.queue[1]) - @parameterized.expand([ - ('result', 'self.transformed_data_example_result',), - ('error', 'self.transformed_data_example_general_error',), - ]) - def test_place_latest_data_on_queue_raises_key_error_if_keys_missing( - self, response_index_key, transformed_data) -> None: - invalid_transformed_data = copy.deepcopy(eval(transformed_data)) - del invalid_transformed_data[response_index_key]['meta_data'] - self.assertRaises( - KeyError, self.test_data_transformer._place_latest_data_on_queue, - invalid_transformed_data, {}, {}) - @parameterized.expand([({}, False,), ('self.test_state', True), ]) @mock.patch.object(SystemDataTransformer, "_transform_data") @mock.patch.object(RabbitMQApi, "basic_ack") diff --git a/alerter/test/monitors/contracts/test_chainlink.py b/alerter/test/monitors/contracts/test_chainlink.py index fc16277dc..64f319091 100644 --- a/alerter/test/monitors/contracts/test_chainlink.py +++ b/alerter/test/monitors/contracts/test_chainlink.py @@ -12,9 +12,9 @@ import pika from freezegun import freeze_time from parameterized import parameterized -from requests.exceptions import (ConnectionError as ReqConnectionError, - ReadTimeout, ChunkedEncodingError, - MissingSchema, InvalidSchema, InvalidURL) +from requests.exceptions import ( + ConnectionError as ReqConnectionError, ReadTimeout, ChunkedEncodingError, + MissingSchema, InvalidSchema, InvalidURL) from urllib3.exceptions import ProtocolError from web3 import Web3 from web3.contract import ContractFunction, ContractEvent @@ -31,11 +31,10 @@ HEALTH_CHECK_EXCHANGE, RAW_DATA_EXCHANGE, HEARTBEAT_OUTPUT_WORKER_ROUTING_KEY, CHAINLINK_CONTRACTS_RAW_DATA_ROUTING_KEY) -from src.utils.exceptions import (PANICException, - ComponentNotGivenEnoughDataSourcesException, - MetricNotFoundException, - CouldNotRetrieveContractsException, - NoSyncedDataSourceWasAccessibleException) +from src.utils.exceptions import ( + PANICException, ComponentNotGivenEnoughDataSourcesException, + MetricNotFoundException, CouldNotRetrieveContractsException, + NoSyncedDataSourceWasAccessibleException) from test.test_utils.utils import ( connect_to_rabbit, delete_queue_if_exists, delete_exchange_if_exists, disconnect_from_rabbit) @@ -87,23 +86,23 @@ def setUp(self) -> None: 'timestamp': datetime(2012, 1, 1).timestamp(), } self.test_queue_name = 'Test Queue' - self.eth_address_1 = "0x4562845f37813a201b9ddb52e57a902659b7ae6a" + self.address_1 = "0x4562845f37813a201b9ddb52e57a902659b7ae6a" self.retrieved_prom_data_1 = { 'eth_balance': { '{"account": "0x4562845f37813a201b9ddb52e57a902659b7ae6a"}': 26.043292035081947 }, } - self.eth_address_2 = "0x2607e6f021922a5483d64935f87e15ea797fe8d4" + self.address_2 = "0x2607e6f021922a5483d64935f87e15ea797fe8d4" self.retrieved_prom_data_2 = { 'eth_balance': { '{"account": "0x2607e6f021922a5483d64935f87e15ea797fe8d4"}': 45.043292035081947 }, } - self.node_eth_address_example = { - self.node_id_1: self.eth_address_1, - self.node_id_2: self.eth_address_2 + self.node_address_example = { + self.node_id_1: self.address_1, + self.node_id_2: self.address_2 } self.proxy_address_1 = '0xFDF9EB5fafc11Efa65f6FD144898da39a7920Ae8' self.proxy_address_2 = '0x678df3415fc31947dA4324eC63212874be5a82f8' @@ -144,16 +143,16 @@ def setUp(self) -> None: } ] self.contract_1_oracles = [ - self.eth_address_1, self.eth_address_2, 'irrelevant_address_1', + self.address_1, self.address_2, 'irrelevant_address_1', 'irrelevant_address_2'] self.contract_2_oracles = [ - self.eth_address_1, 'irrelevant_address_1', 'irrelevant_address_2'] + self.address_1, 'irrelevant_address_1', 'irrelevant_address_2'] self.contract_3_transmitters = [ - self.eth_address_2, self.eth_address_1, 'irrelevant_address_1', + self.address_2, self.address_1, 'irrelevant_address_1', 'irrelevant_address_2' ] self.contract_4_transmitters = [ - self.eth_address_2, 'irrelevant_address_1', 'irrelevant_address_2' + self.address_2, 'irrelevant_address_1', 'irrelevant_address_2' ] self.filtered_contracts_example = { self.node_id_1: { @@ -230,10 +229,9 @@ def test_evm_node_w3_interface_returns_evm_node_w3_interface(self) -> None: def test_contracts_url_returns_wei_watchers_url(self) -> None: self.assertEqual(self.weiwatchers_url, self.test_monitor.contracts_url) - def test_node_eth_address_returns_node_eth_address(self) -> None: - self.test_monitor._node_eth_address = self.test_data_dict - self.assertEqual(self.test_data_dict, - self.test_monitor.node_eth_address) + def test_node_address_returns_node_address(self) -> None: + self.test_monitor._node_address = self.test_data_dict + self.assertEqual(self.test_data_dict, self.test_monitor.node_address) def test_contracts_data_returns_contracts_data(self) -> None: self.test_monitor._contracts_data = self.test_data_dict @@ -261,11 +259,11 @@ def test_wei_watchers_retrieval_limiter_returns_weiwatchers_limiter( self.assertEqual(self.test_data_dict, self.test_monitor.wei_watchers_retrieval_limiter) - def test_eth_address_retrieval_limiter_returns_eth_address_limiter( + def test_address_retrieval_limiter_returns_address_limiter( self) -> None: - self.test_monitor._eth_address_retrieval_limiter = self.test_data_dict + self.test_monitor._address_retrieval_limiter = self.test_data_dict self.assertEqual(self.test_data_dict, - self.test_monitor.eth_address_retrieval_limiter) + self.test_monitor.address_retrieval_limiter) def test_ChainlinkContractsMonitor_init_raises_except_if_nodes_lists_empty( self) -> None: @@ -410,7 +408,7 @@ def test_store_chain_contracts_stores_contracts_data(self) -> None: self.test_monitor.contracts_data) @mock.patch("src.monitors.contracts.chainlink.get_prometheus_metrics_data") - def test_get_nodes_eth_address_returns_correctly_if_no_errors( + def test_get_nodes_address_returns_correctly_if_no_errors( self, mock_get_prom_metrics_data) -> None: """ In this test we will assume that the prometheus metrics will be returned @@ -418,11 +416,11 @@ def test_get_nodes_eth_address_returns_correctly_if_no_errors( """ mock_get_prom_metrics_data.side_effect = [self.retrieved_prom_data_1, self.retrieved_prom_data_2] - actual = self.test_monitor._get_nodes_eth_address() + actual = self.test_monitor._get_nodes_address() expected = ( { - self.node_id_1: self.eth_address_1, - self.node_id_2: self.eth_address_2, + self.node_id_1: self.address_1, + self.node_id_2: self.address_2, }, False ) self.assertEqual(expected, actual) @@ -435,7 +433,7 @@ def test_get_nodes_eth_address_returns_correctly_if_no_errors( (MetricNotFoundException('test_metric', 'test_endpoint'),), ]) @mock.patch("src.monitors.contracts.chainlink.get_prometheus_metrics_data") - def test_get_nodes_eth_address_returns_correctly_if_prom_retrieval_errors( + def test_get_nodes_address_returns_correctly_if_prom_retrieval_errors( self, error_instance, mock_get_prom_metrics_data) -> None: """ This test will be performed for 3 scenarios, for when the first @@ -450,8 +448,8 @@ def test_get_nodes_eth_address_returns_correctly_if_prom_retrieval_errors( if type(error_instance) == MetricNotFoundException \ else [self.retrieved_prom_data_1, error_instance, error_instance, error_instance] - actual = self.test_monitor._get_nodes_eth_address() - expected = ({self.node_id_1: self.eth_address_1}, True) + actual = self.test_monitor._get_nodes_address() + expected = ({self.node_id_1: self.address_1}, True) self.assertEqual(expected, actual) mock_get_prom_metrics_data.reset_mock() @@ -461,8 +459,8 @@ def test_get_nodes_eth_address_returns_correctly_if_prom_retrieval_errors( if type(error_instance) == MetricNotFoundException \ else [error_instance, error_instance, error_instance, self.retrieved_prom_data_2] - actual = self.test_monitor._get_nodes_eth_address() - expected = ({self.node_id_2: self.eth_address_2}, True) + actual = self.test_monitor._get_nodes_address() + expected = ({self.node_id_2: self.address_2}, True) self.assertEqual(expected, actual) mock_get_prom_metrics_data.reset_mock() @@ -472,15 +470,15 @@ def test_get_nodes_eth_address_returns_correctly_if_prom_retrieval_errors( if type(error_instance) == MetricNotFoundException \ else [error_instance, error_instance, error_instance, error_instance, error_instance, error_instance] - actual = self.test_monitor._get_nodes_eth_address() + actual = self.test_monitor._get_nodes_address() expected = ({}, True) self.assertEqual(expected, actual) - def test_store_nodes_eth_addresses_stores_node_eth_address(self) -> None: - self.assertEqual({}, self.test_monitor.node_eth_address) - self.test_monitor._store_nodes_eth_addresses(self.test_data_dict) + def test_store_nodes_addresses_stores_node_address(self) -> None: + self.assertEqual({}, self.test_monitor.node_address) + self.test_monitor._store_nodes_addresses(self.test_data_dict) self.assertEqual(self.test_data_dict, - self.test_monitor.node_eth_address) + self.test_monitor.node_address) @mock.patch.object(BaseEth, '_is_syncing') @mock.patch.object(Web3, 'isConnected') @@ -583,9 +581,9 @@ def test_filter_contracts_by_node_filters_correctly( one declared in the setUp function. This is used to check if contracts are filtered according to which nodes are participating on them. """ - self.test_monitor._node_eth_address = self.node_eth_address_example + self.test_monitor._node_address = self.node_address_example self.test_monitor._contracts_data = self.retrieved_contracts_example - mock_to_checksum.side_effect = [self.eth_address_1, self.eth_address_2] + mock_to_checksum.side_effect = [self.address_1, self.address_2] mock_call.side_effect = [ self.contract_1_oracles, self.contract_2_oracles, self.contract_3_transmitters, self.contract_4_transmitters, @@ -612,7 +610,7 @@ def test_get_v3_data_returns_empty_dict_if_node_id_was_not_filtered( selected_node = self.evm_nodes[0] actual = self.test_monitor._get_v3_data( self.test_monitor.evm_node_w3_interface[selected_node], - self.eth_address_1, self.node_id_1) + self.address_1, self.node_id_1) self.assertEqual({}, actual) @mock.patch.object(ContractFunction, "call") @@ -628,7 +626,7 @@ def test_get_v3_data_creates_filter_correctly_first_time_round( (the first block to query is the current). For this test we will use the first node, which has 2 v3 contracts associated with it. """ - mock_to_checksum.return_value = self.eth_address_1 + mock_to_checksum.return_value = self.address_1 mock_get_block.return_value = {'number': self.current_block} mock_create_filter.return_value = TestEventsClass([]) mock_call.side_effect = [ @@ -646,13 +644,13 @@ def test_get_v3_data_creates_filter_correctly_first_time_round( self.test_monitor._get_v3_data( self.test_monitor.evm_node_w3_interface[selected_node], - self.eth_address_1, self.node_id_1) + self.address_1, self.node_id_1) actual_calls = mock_create_filter.call_args_list expected_calls = [ call(fromBlock=self.current_block, toBlock=self.current_block, - argument_filters={'oracle': self.eth_address_1}), + argument_filters={'oracle': self.address_1}), call(fromBlock=self.current_block, toBlock=self.current_block, - argument_filters={'oracle': self.eth_address_1}) + argument_filters={'oracle': self.address_1}) ] self.assertEqual(expected_calls, actual_calls) @@ -675,7 +673,7 @@ def test_get_v3_data_calls_filter_correctly_second_time_round( self.proxy_address_1] = self.current_block - 2 self.test_monitor._last_block_monitored[self.node_id_1][ self.proxy_address_2] = self.current_block - 2 - mock_to_checksum.return_value = self.eth_address_1 + mock_to_checksum.return_value = self.address_1 mock_get_block.return_value = {'number': self.current_block} mock_create_filter.return_value = TestEventsClass([]) mock_call.side_effect = [ @@ -693,13 +691,13 @@ def test_get_v3_data_calls_filter_correctly_second_time_round( self.test_monitor._get_v3_data( self.test_monitor.evm_node_w3_interface[selected_node], - self.eth_address_1, self.node_id_1) + self.address_1, self.node_id_1) actual_calls = mock_create_filter.call_args_list expected_calls = [ call(fromBlock=self.current_block - 1, toBlock=self.current_block, - argument_filters={'oracle': self.eth_address_1}), + argument_filters={'oracle': self.address_1}), call(fromBlock=self.current_block - 1, toBlock=self.current_block, - argument_filters={'oracle': self.eth_address_1}) + argument_filters={'oracle': self.address_1}) ] self.assertEqual(expected_calls, actual_calls) @@ -714,7 +712,7 @@ def test_get_v3_data_return_if_no_rounds_recorded( This test covers the scenario where no round answers were submitted by the node in-between blocks """ - mock_to_checksum.return_value = self.eth_address_1 + mock_to_checksum.return_value = self.address_1 mock_get_block.return_value = {'number': self.current_block} mock_create_filter.return_value = TestEventsClass([]) mock_call.side_effect = [ @@ -732,7 +730,7 @@ def test_get_v3_data_return_if_no_rounds_recorded( actual_return = self.test_monitor._get_v3_data( self.test_monitor.evm_node_w3_interface[selected_node], - self.eth_address_1, self.node_id_1) + self.address_1, self.node_id_1) expected_return = { self.proxy_address_1: { 'contractVersion': 3, @@ -773,7 +771,7 @@ def test_get_v3_data_return_if_some_rounds_with_consensus_recorded( by the node in-between blocks, and a round consensus was reached already. """ - mock_to_checksum.return_value = self.eth_address_1 + mock_to_checksum.return_value = self.address_1 mock_get_block.return_value = {'number': self.current_block} mock_create_filter.return_value = TestEventsClass([ { @@ -812,7 +810,7 @@ def test_get_v3_data_return_if_some_rounds_with_consensus_recorded( actual_return = self.test_monitor._get_v3_data( self.test_monitor.evm_node_w3_interface[selected_node], - self.eth_address_1, self.node_id_1) + self.address_1, self.node_id_1) expected_return = { self.proxy_address_1: { 'contractVersion': 3, @@ -883,7 +881,7 @@ def test_get_v3_data_return_if_some_rounds_without_consensus_recorded( by the node in-between blocks, and a round consensus has not been reached yet. """ - mock_to_checksum.return_value = self.eth_address_1 + mock_to_checksum.return_value = self.address_1 mock_get_block.return_value = {'number': self.current_block} mock_create_filter.return_value = TestEventsClass([ { @@ -909,7 +907,7 @@ def test_get_v3_data_return_if_some_rounds_without_consensus_recorded( actual_return = self.test_monitor._get_v3_data( self.test_monitor.evm_node_w3_interface[selected_node], - self.eth_address_1, self.node_id_1) + self.address_1, self.node_id_1) expected_return = { self.proxy_address_1: { 'contractVersion': 3, @@ -968,7 +966,7 @@ def test_get_v4_data_returns_empty_dict_if_node_id_was_not_filtered( selected_node = self.evm_nodes[0] actual = self.test_monitor._get_v4_data( self.test_monitor.evm_node_w3_interface[selected_node], - self.eth_address_2, self.node_id_2) + self.address_2, self.node_id_2) self.assertEqual({}, actual) @mock.patch.object(ContractFunction, "call") @@ -984,7 +982,7 @@ def test_get_v4_data_creates_filter_correctly_first_time_round( (the first block to query is the current). For this test we will use the second node, which has 2 v4 contracts associated with it. """ - mock_to_checksum.return_value = self.eth_address_2 + mock_to_checksum.return_value = self.address_2 mock_get_block.return_value = {'number': self.current_block} mock_create_filter.return_value = TestEventsClass([]) mock_call.side_effect = [ @@ -1002,7 +1000,7 @@ def test_get_v4_data_creates_filter_correctly_first_time_round( self.test_monitor._get_v4_data( self.test_monitor.evm_node_w3_interface[selected_node], - self.eth_address_2, self.node_id_2) + self.address_2, self.node_id_2) actual_calls = mock_create_filter.call_args_list expected_calls = [ call(fromBlock=self.current_block, toBlock=self.current_block), @@ -1029,7 +1027,7 @@ def test_get_v4_data_calls_filter_correctly_second_time_round( self.proxy_address_3] = self.current_block - 2 self.test_monitor._last_block_monitored[self.node_id_2][ self.proxy_address_4] = self.current_block - 2 - mock_to_checksum.return_value = self.eth_address_2 + mock_to_checksum.return_value = self.address_2 mock_get_block.return_value = {'number': self.current_block} mock_create_filter.return_value = TestEventsClass([]) mock_call.side_effect = [ @@ -1047,7 +1045,7 @@ def test_get_v4_data_calls_filter_correctly_second_time_round( self.test_monitor._get_v4_data( self.test_monitor.evm_node_w3_interface[selected_node], - self.eth_address_2, self.node_id_2) + self.address_2, self.node_id_2) actual_calls = mock_create_filter.call_args_list expected_calls = [ call(fromBlock=self.current_block - 1, toBlock=self.current_block), @@ -1066,7 +1064,7 @@ def test_get_v4_data_return_if_no_rounds_transmitted( This test covers the scenario where no round results were transmitted yet in-between blocks """ - mock_to_checksum.return_value = self.eth_address_2 + mock_to_checksum.return_value = self.address_2 mock_get_block.return_value = {'number': self.current_block} mock_create_filter.return_value = TestEventsClass([]) mock_call.side_effect = [ @@ -1084,7 +1082,7 @@ def test_get_v4_data_return_if_no_rounds_transmitted( actual_return = self.test_monitor._get_v4_data( self.test_monitor.evm_node_w3_interface[selected_node], - self.eth_address_2, self.node_id_2) + self.address_2, self.node_id_2) expected_return = { self.proxy_address_3: { 'contractVersion': 4, @@ -1124,8 +1122,8 @@ def test_get_v4_data_ignores_contracts_if_node_no_longer_participating( In this test we will check that if a node is no longer a participant of a contract, then it is ignored such that no data is returned for it. """ - self.contract_3_transmitters.remove(self.eth_address_2) - mock_to_checksum.return_value = self.eth_address_2 + self.contract_3_transmitters.remove(self.address_2) + mock_to_checksum.return_value = self.address_2 mock_get_block.return_value = {'number': self.current_block} mock_create_filter.return_value = TestEventsClass([]) mock_call.side_effect = [ @@ -1143,7 +1141,7 @@ def test_get_v4_data_ignores_contracts_if_node_no_longer_participating( actual_return = self.test_monitor._get_v4_data( self.test_monitor.evm_node_w3_interface[selected_node], - self.eth_address_2, self.node_id_2) + self.address_2, self.node_id_2) expected_return = { self.proxy_address_4: { 'contractVersion': 4, @@ -1171,7 +1169,7 @@ def test_get_v4_data_return_if_some_rounds_recorded_and_node_sent_answer( This test covers the scenario where round answers were transmitted in-between blocks, and the node has submitted an answer. """ - mock_to_checksum.return_value = self.eth_address_2 + mock_to_checksum.return_value = self.address_2 mock_get_block.return_value = {'number': self.current_block} mock_create_filter.return_value = TestEventsClass([ { @@ -1214,7 +1212,7 @@ def test_get_v4_data_return_if_some_rounds_recorded_and_node_sent_answer( actual_return = self.test_monitor._get_v4_data( self.test_monitor.evm_node_w3_interface[selected_node], - self.eth_address_2, self.node_id_2) + self.address_2, self.node_id_2) expected_return = { self.proxy_address_3: { 'contractVersion': 4, @@ -1292,7 +1290,7 @@ def test_get_v4_data_return_if_some_rounds_recorded_and_no_node_answer( This test covers the scenario where round answers were transmitted in-between blocks, and the node did not submit its answer. """ - mock_to_checksum.return_value = self.eth_address_2 + mock_to_checksum.return_value = self.address_2 mock_get_block.return_value = {'number': self.current_block} mock_create_filter.return_value = TestEventsClass([ { @@ -1335,7 +1333,7 @@ def test_get_v4_data_return_if_some_rounds_recorded_and_no_node_answer( actual_return = self.test_monitor._get_v4_data( self.test_monitor.evm_node_w3_interface[selected_node], - self.eth_address_2, self.node_id_2) + self.address_2, self.node_id_2) expected_return = { self.proxy_address_3: { 'contractVersion': 4, @@ -1417,7 +1415,7 @@ def test_get_data_return(self, mock_get_v3_data, mock_get_v4_data) -> None: actual_return = self.test_monitor._get_data( self.test_monitor.evm_node_w3_interface[selected_node], - self.eth_address_1, self.node_id_1) + self.address_1, self.node_id_1) expected_return = { 'v3_data_key': 'v3_data_value', 'v4_data_key': 'v4_data_value' @@ -1513,12 +1511,12 @@ def test_get_node_config_by_node_id_returns_correctly(self) -> None: @mock.patch.object(ChainlinkContractsMonitor, '_send_heartbeat') @mock.patch.object(ChainlinkContractsMonitor, '_send_data') @mock.patch.object(ChainlinkContractsMonitor, '_select_node') - @mock.patch.object(ChainlinkContractsMonitor, '_get_nodes_eth_address') + @mock.patch.object(ChainlinkContractsMonitor, '_get_nodes_address') @mock.patch.object(ChainlinkContractsMonitor, '_store_chain_contracts') @mock.patch.object(ChainlinkContractsMonitor, '_get_chain_contracts') def test_monitor_retrieves_data_from_weiwatchers_periodically( self, mock_get_chain_contracts, mock_store_chain_contracts, - mock_get_nodes_eth_address, mock_select_node, mock_send_data, + mock_get_nodes_address, mock_select_node, mock_send_data, mock_send_heartbeat) -> None: """ In this test we will check that wei-watchers data is retrieved @@ -1527,7 +1525,7 @@ def test_monitor_retrieves_data_from_weiwatchers_periodically( """ mock_get_chain_contracts.return_value = self.test_data_dict mock_store_chain_contracts.return_value = None - mock_get_nodes_eth_address.return_value = (None, True) + mock_get_nodes_address.return_value = (None, True) mock_select_node.return_value = None mock_send_data.return_value = None mock_send_heartbeat.return_value = None @@ -1564,13 +1562,13 @@ def test_monitor_retrieves_data_from_weiwatchers_periodically( @mock.patch.object(ChainlinkContractsMonitor, '_send_heartbeat') @mock.patch.object(ChainlinkContractsMonitor, '_send_data') @mock.patch.object(ChainlinkContractsMonitor, '_select_node') - @mock.patch.object(ChainlinkContractsMonitor, '_store_nodes_eth_addresses') - @mock.patch.object(ChainlinkContractsMonitor, '_get_nodes_eth_address') + @mock.patch.object(ChainlinkContractsMonitor, '_store_nodes_addresses') + @mock.patch.object(ChainlinkContractsMonitor, '_get_nodes_address') @mock.patch.object(ChainlinkContractsMonitor, '_store_chain_contracts') @mock.patch.object(ChainlinkContractsMonitor, '_get_chain_contracts') - def test_monitor_retrieves_nodes_eth_address_periodically( + def test_monitor_retrieves_nodes_address_periodically( self, mock_get_chain_contracts, mock_store_chain_contracts, - mock_get_nodes_eth_address, mock_store_nodes_eth_addresses, + mock_get_nodes_address, mock_store_nodes_addresses, mock_select_node, mock_send_data, mock_send_heartbeat) -> None: """ In this test we will check that prometheus data is retrieved @@ -1579,8 +1577,8 @@ def test_monitor_retrieves_nodes_eth_address_periodically( """ mock_get_chain_contracts.return_value = None mock_store_chain_contracts.return_value = None - mock_get_nodes_eth_address.return_value = (self.test_data_dict, False) - mock_store_nodes_eth_addresses.return_value = None + mock_get_nodes_address.return_value = (self.test_data_dict, False) + mock_store_nodes_addresses.return_value = None mock_select_node.return_value = None mock_send_data.return_value = None mock_send_heartbeat.return_value = None @@ -1589,43 +1587,43 @@ def test_monitor_retrieves_nodes_eth_address_periodically( # Check that data from prometheus is retrieved and stored first time # round self.test_monitor._monitor() - mock_get_nodes_eth_address.assert_called_once() - mock_store_nodes_eth_addresses.assert_called_once_with( + mock_get_nodes_address.assert_called_once() + mock_store_nodes_addresses.assert_called_once_with( self.test_data_dict) - mock_get_nodes_eth_address.reset_mock() - mock_store_nodes_eth_addresses.reset_mock() + mock_get_nodes_address.reset_mock() + mock_store_nodes_addresses.reset_mock() # Check that data from prometheus is not retrieved if not enough time # passes - self.test_monitor.eth_address_retrieval_limiter. \ + self.test_monitor.address_retrieval_limiter. \ _last_time_that_did_task = \ datetime.fromtimestamp(datetime.now().timestamp() - period + 1) self.test_monitor._monitor() - mock_get_nodes_eth_address.assert_not_called() - mock_store_nodes_eth_addresses.assert_not_called() - mock_get_nodes_eth_address.reset_mock() - mock_store_nodes_eth_addresses.reset_mock() + mock_get_nodes_address.assert_not_called() + mock_store_nodes_addresses.assert_not_called() + mock_get_nodes_address.reset_mock() + mock_store_nodes_addresses.reset_mock() # Check that data from prometheus is retrieved if enough time passes - self.test_monitor.eth_address_retrieval_limiter. \ + self.test_monitor.address_retrieval_limiter. \ _last_time_that_did_task = \ datetime.fromtimestamp(datetime.now().timestamp() - period - 1) self.test_monitor._monitor() - mock_get_nodes_eth_address.assert_called_once() - mock_store_nodes_eth_addresses.assert_called_once_with( + mock_get_nodes_address.assert_called_once() + mock_store_nodes_addresses.assert_called_once_with( self.test_data_dict) @freeze_time("2012-01-01") @mock.patch.object(ChainlinkContractsMonitor, '_send_heartbeat') @mock.patch.object(ChainlinkContractsMonitor, '_send_data') @mock.patch.object(ChainlinkContractsMonitor, '_select_node') - @mock.patch.object(ChainlinkContractsMonitor, '_store_nodes_eth_addresses') - @mock.patch.object(ChainlinkContractsMonitor, '_get_nodes_eth_address') + @mock.patch.object(ChainlinkContractsMonitor, '_store_nodes_addresses') + @mock.patch.object(ChainlinkContractsMonitor, '_get_nodes_address') @mock.patch.object(ChainlinkContractsMonitor, '_store_chain_contracts') @mock.patch.object(ChainlinkContractsMonitor, '_get_chain_contracts') def test_monitor_retrieves_prometheus_data_if_previous_retrieval_failed( self, mock_get_chain_contracts, mock_store_chain_contracts, - mock_get_nodes_eth_address, mock_store_nodes_eth_addresses, + mock_get_nodes_address, mock_store_nodes_addresses, mock_select_node, mock_send_data, mock_send_heartbeat) -> None: """ In this test we will check that if the self._monitor function fails in @@ -1634,8 +1632,8 @@ def test_monitor_retrieves_prometheus_data_if_previous_retrieval_failed( """ mock_get_chain_contracts.return_value = None mock_store_chain_contracts.return_value = None - mock_get_nodes_eth_address.return_value = (self.test_data_dict, True) - mock_store_nodes_eth_addresses.return_value = None + mock_get_nodes_address.return_value = (self.test_data_dict, True) + mock_store_nodes_addresses.return_value = None mock_select_node.return_value = None mock_send_data.return_value = None mock_send_heartbeat.return_value = None @@ -1643,20 +1641,20 @@ def test_monitor_retrieves_prometheus_data_if_previous_retrieval_failed( # Check that data from prometheus is retrieved and stored first time # round self.test_monitor._monitor() - mock_get_nodes_eth_address.assert_called_once() - mock_store_nodes_eth_addresses.assert_called_once_with( + mock_get_nodes_address.assert_called_once() + mock_store_nodes_addresses.assert_called_once_with( self.test_data_dict) - mock_get_nodes_eth_address.reset_mock() - mock_store_nodes_eth_addresses.reset_mock() + mock_get_nodes_address.reset_mock() + mock_store_nodes_addresses.reset_mock() # Check that data from prometheus is retrieved again since retrieval # has failed self.test_monitor._monitor() - mock_get_nodes_eth_address.assert_called_once() - mock_store_nodes_eth_addresses.assert_called_once_with( + mock_get_nodes_address.assert_called_once() + mock_store_nodes_addresses.assert_called_once_with( self.test_data_dict) - mock_get_nodes_eth_address.reset_mock() - mock_store_nodes_eth_addresses.reset_mock() + mock_get_nodes_address.reset_mock() + mock_store_nodes_addresses.reset_mock() @parameterized.expand([ (ReqConnectionError('test'),), (ReadTimeout('test'),), @@ -1668,14 +1666,14 @@ def test_monitor_retrieves_prometheus_data_if_previous_retrieval_failed( @mock.patch.object(ChainlinkContractsMonitor, '_send_heartbeat') @mock.patch.object(ChainlinkContractsMonitor, '_send_data') @mock.patch.object(ChainlinkContractsMonitor, '_select_node') - @mock.patch.object(ChainlinkContractsMonitor, '_store_nodes_eth_addresses') - @mock.patch.object(ChainlinkContractsMonitor, '_get_nodes_eth_address') + @mock.patch.object(ChainlinkContractsMonitor, '_store_nodes_addresses') + @mock.patch.object(ChainlinkContractsMonitor, '_get_nodes_address') @mock.patch.object(ChainlinkContractsMonitor, '_store_chain_contracts') @mock.patch.object(ChainlinkContractsMonitor, '_get_chain_contracts') def test_monitor_processes_and_sends_error_and_hb_if_weiwatchers_exception( self, exception, mock_get_chain_contracts, - mock_store_chain_contracts, mock_get_nodes_eth_address, - mock_store_nodes_eth_addresses, mock_select_node, mock_send_data, + mock_store_chain_contracts, mock_get_nodes_address, + mock_store_nodes_addresses, mock_select_node, mock_send_data, mock_send_heartbeat) -> None: """ In this test we will check that if data from wei-watchers could not be @@ -1684,8 +1682,8 @@ def test_monitor_processes_and_sends_error_and_hb_if_weiwatchers_exception( """ mock_get_chain_contracts.side_effect = exception mock_store_chain_contracts.return_value = None - mock_get_nodes_eth_address.return_value = (self.test_data_dict, False) - mock_store_nodes_eth_addresses.return_value = None + mock_get_nodes_address.return_value = (self.test_data_dict, False) + mock_store_nodes_addresses.return_value = None mock_select_node.return_value = None mock_send_data.return_value = None mock_send_heartbeat.return_value = None @@ -1716,13 +1714,13 @@ def test_monitor_processes_and_sends_error_and_hb_if_weiwatchers_exception( @mock.patch.object(ChainlinkContractsMonitor, '_send_heartbeat') @mock.patch.object(ChainlinkContractsMonitor, '_send_data') @mock.patch.object(ChainlinkContractsMonitor, '_select_node') - @mock.patch.object(ChainlinkContractsMonitor, '_store_nodes_eth_addresses') - @mock.patch.object(ChainlinkContractsMonitor, '_get_nodes_eth_address') + @mock.patch.object(ChainlinkContractsMonitor, '_store_nodes_addresses') + @mock.patch.object(ChainlinkContractsMonitor, '_get_nodes_address') @mock.patch.object(ChainlinkContractsMonitor, '_store_chain_contracts') @mock.patch.object(ChainlinkContractsMonitor, '_get_chain_contracts') def test_monitor_processes_and_sends_error_and_hb_if_no_evm_node_selected( self, mock_get_chain_contracts, mock_store_chain_contracts, - mock_get_nodes_eth_address, mock_store_nodes_eth_addresses, + mock_get_nodes_address, mock_store_nodes_addresses, mock_select_node, mock_send_data, mock_send_heartbeat) -> None: """ In this test we will check that if no evm node is selected, then a @@ -1731,8 +1729,8 @@ def test_monitor_processes_and_sends_error_and_hb_if_no_evm_node_selected( """ mock_get_chain_contracts.return_value = None mock_store_chain_contracts.return_value = None - mock_get_nodes_eth_address.return_value = (self.test_data_dict, False) - mock_store_nodes_eth_addresses.return_value = None + mock_get_nodes_address.return_value = (self.test_data_dict, False) + mock_store_nodes_addresses.return_value = None mock_select_node.return_value = None mock_send_data.return_value = None mock_send_heartbeat.return_value = None @@ -1765,15 +1763,15 @@ def test_monitor_processes_and_sends_error_and_hb_if_no_evm_node_selected( @mock.patch.object(ChainlinkContractsMonitor, '_send_heartbeat') @mock.patch.object(ChainlinkContractsMonitor, '_send_data') @mock.patch.object(ChainlinkContractsMonitor, '_select_node') - @mock.patch.object(ChainlinkContractsMonitor, '_get_nodes_eth_address') + @mock.patch.object(ChainlinkContractsMonitor, '_get_nodes_address') @mock.patch.object(ChainlinkContractsMonitor, '_get_chain_contracts') def test_monitor_gets_data_for_each_node_processes_it_and_sends_it_and_hb( - self, mock_get_chain_contracts, mock_get_nodes_eth_address, + self, mock_get_chain_contracts, mock_get_nodes_address, mock_select_node, mock_send_data, mock_send_heartbeat, mock_get_data, mock_filter_contracts_by_node) -> None: mock_get_chain_contracts.return_value = self.retrieved_contracts_example - mock_get_nodes_eth_address.return_value = ( - self.node_eth_address_example, + mock_get_nodes_address.return_value = ( + self.node_address_example, False ) mock_select_node.return_value = self.evm_nodes[0] @@ -1822,15 +1820,15 @@ def test_monitor_gets_data_for_each_node_processes_it_and_sends_it_and_hb( @mock.patch.object(ChainlinkContractsMonitor, '_send_heartbeat') @mock.patch.object(ChainlinkContractsMonitor, '_send_data') @mock.patch.object(ChainlinkContractsMonitor, '_select_node') - @mock.patch.object(ChainlinkContractsMonitor, '_get_nodes_eth_address') + @mock.patch.object(ChainlinkContractsMonitor, '_get_nodes_address') @mock.patch.object(ChainlinkContractsMonitor, '_get_chain_contracts') def test_monitor_skips_node_if_data_retrieval_fails_for_node( - self, mock_get_chain_contracts, mock_get_nodes_eth_address, + self, mock_get_chain_contracts, mock_get_nodes_address, mock_select_node, mock_send_data, mock_send_heartbeat, mock_get_data, mock_filter_contracts_by_node) -> None: mock_get_chain_contracts.return_value = self.retrieved_contracts_example - mock_get_nodes_eth_address.return_value = ( - self.node_eth_address_example, + mock_get_nodes_address.return_value = ( + self.node_address_example, False ) mock_select_node.return_value = self.evm_nodes[0] diff --git a/alerter/test/monitors/managers/test_node.py b/alerter/test/monitors/managers/test_node.py index df02d1d80..73b05fa0b 100644 --- a/alerter/test/monitors/managers/test_node.py +++ b/alerter/test/monitors/managers/test_node.py @@ -565,7 +565,7 @@ def test_initialise_rabbitmq_initialises_everything_as_expected( self.test_manager.rabbitmq.basic_publish_confirm( exchange=CONFIG_EXCHANGE, routing_key=EVM_NODES_CONFIGS_ROUTING_KEY_CHAINS, - body=self.test_data_str,is_body_dict=False, + body=self.test_data_str, is_body_dict=False, properties=pika.BasicProperties(delivery_mode=2), mandatory=True) # Re-declare queues to get the number of messages and the msgs received diff --git a/alerter/test/monitors/node/test_chainlink.py b/alerter/test/monitors/node/test_chainlink.py index 487d6e91e..fa9737afb 100644 --- a/alerter/test/monitors/node/test_chainlink.py +++ b/alerter/test/monitors/node/test_chainlink.py @@ -11,6 +11,7 @@ from unittest.mock import call import pika +from dateutil import parser from freezegun import freeze_time from parameterized import parameterized from pika.exceptions import AMQPConnectionError, AMQPChannelError @@ -62,6 +63,7 @@ def setUp(self) -> None: 'test_key_1': 'test_val_1', 'test_key_2': 'test_val_2', } + self.test_symbol = 'TEST' self.test_heartbeat = { 'component_name': 'Test Component', 'is_alive': True, @@ -166,9 +168,10 @@ def setUp(self) -> None: 'percentile': '20%', 'price': 5000000000.0 }, - 'eth_balance': { + 'balance': { 'address': 'eth_add_1', - 'balance': 26.043292035081947 + 'balance': 26.043292035081947, + 'symbol': self.test_symbol }, 'run_status_update_total_errors': 8 } @@ -407,7 +410,7 @@ def test_display_data_returns_the_correct_string_if_all_metrics_present( "tx_manager_num_gas_bumps_total={}, " \ "tx_manager_gas_bump_exceeds_limit_total={}, " \ "unconfirmed_transactions={}, gas_updater_set_gas_price={}, " \ - "eth_balance={}, run_status_update_total_errors={}" \ + "balance={}, run_status_update_total_errors={}" \ "".format( self.processed_prometheus_data_example[ 'head_tracker_current_head'], @@ -425,7 +428,7 @@ def test_display_data_returns_the_correct_string_if_all_metrics_present( 'unconfirmed_transactions'], self.processed_prometheus_data_example[ 'gas_updater_set_gas_price'], - self.processed_prometheus_data_example['eth_balance'], + self.processed_prometheus_data_example['balance'], self.processed_prometheus_data_example[ 'run_status_update_total_errors'] ) @@ -443,7 +446,7 @@ def test_display_data_returns_the_correct_string_if_all_metrics_present( "tx_manager_num_gas_bumps_total={}, " \ "tx_manager_gas_bump_exceeds_limit_total={}, " \ "unconfirmed_transactions={}, gas_updater_set_gas_price={}, " \ - "eth_balance={}, run_status_update_total_errors={}" \ + "balance={}, run_status_update_total_errors={}" \ "".format( self.processed_prometheus_data_example_optionals_none[ 'head_tracker_current_head'], @@ -462,7 +465,7 @@ def test_display_data_returns_the_correct_string_if_all_metrics_present( self.processed_prometheus_data_example_optionals_none[ 'gas_updater_set_gas_price'], self.processed_prometheus_data_example_optionals_none[ - 'eth_balance'], + 'balance'], self.processed_prometheus_data_example_optionals_none[ 'run_status_update_total_errors'] ) @@ -475,7 +478,7 @@ def test_display_data_returns_the_correct_string_if_not_all_metrics_present( self) -> None: # Test when optionals are not None del self.processed_prometheus_data_example['head_tracker_current_head'] - del self.processed_prometheus_data_example['eth_balance'] + del self.processed_prometheus_data_example['balance'] expected_output = \ "head_tracker_current_head={}, " \ "head_tracker_heads_received_total={}, " \ @@ -483,7 +486,7 @@ def test_display_data_returns_the_correct_string_if_not_all_metrics_present( "tx_manager_num_gas_bumps_total={}, " \ "tx_manager_gas_bump_exceeds_limit_total={}, " \ "unconfirmed_transactions={}, gas_updater_set_gas_price={}, " \ - "eth_balance={}, run_status_update_total_errors={}" \ + "balance={}, run_status_update_total_errors={}" \ "".format( "Disabled", self.processed_prometheus_data_example[ @@ -512,8 +515,7 @@ def test_display_data_returns_the_correct_string_if_not_all_metrics_present( # Test when optionals are None del self.processed_prometheus_data_example_optionals_none[ 'head_tracker_current_head'] - del self.processed_prometheus_data_example_optionals_none[ - 'eth_balance'] + del self.processed_prometheus_data_example_optionals_none['balance'] expected_output = \ "head_tracker_current_head={}, " \ "head_tracker_heads_received_total={}, " \ @@ -521,7 +523,7 @@ def test_display_data_returns_the_correct_string_if_not_all_metrics_present( "tx_manager_num_gas_bumps_total={}, " \ "tx_manager_gas_bump_exceeds_limit_total={}, " \ "unconfirmed_transactions={}, gas_updater_set_gas_price={}, " \ - "eth_balance={}, run_status_update_total_errors={}" \ + "balance={}, run_status_update_total_errors={}" \ "".format( "Disabled", self.processed_prometheus_data_example_optionals_none[ @@ -896,8 +898,11 @@ def test_process_error_returns_expected_data(self, "self.retrieved_prometheus_data_example_optionals_none"), ]) @freeze_time("2012-01-01") + @mock.patch.object(ChainlinkNodeMonitor, "_get_currency_symbol") def test_process_retrieved_prometheus_data_returns_expected_data( - self, expected_data_output, retrieved_data) -> None: + self, expected_data_output, retrieved_data, mock_get_symbol + ) -> None: + mock_get_symbol.return_value = self.test_symbol expected_output = { 'result': { 'meta_data': { @@ -959,9 +964,11 @@ def test_send_data_sends_data_correctly(self) -> None: json.loads(body)) @freeze_time("2012-01-01") + @mock.patch.object(ChainlinkNodeMonitor, "_get_currency_symbol") @mock.patch.object(ChainlinkNodeMonitor, "_get_data") def test_monitor_sends_data_and_hb_if_data_retrieve_and_processing_success( - self, mock_get_data) -> None: + self, mock_get_data, mock_get_symbol) -> None: + mock_get_symbol.return_value = self.test_symbol # Here we are assuming that all sources are enabled. expected_output_data = { 'prometheus': { @@ -1253,11 +1260,13 @@ def test_monitor_does_not_send_hb_and_data_if_send_data_fails( self.assertEqual(0, res.method.message_count) @freeze_time("2012-01-01") + @mock.patch.object(ChainlinkNodeMonitor, "_get_currency_symbol") @mock.patch.object(ChainlinkNodeMonitor, "_get_data") def test_monitor_raises_msg_not_del_except_if_hb_not_routed_and_sends_data( - self, mock_get_data) -> None: + self, mock_get_data, mock_get_symbol) -> None: mock_get_data.return_value = \ self.received_retrieval_info_all_source_types_enabled + mock_get_symbol.return_value = self.test_symbol expected_output_data = { 'prometheus': { 'result': { @@ -1311,13 +1320,15 @@ def test_monitor_raises_msg_not_del_except_if_hb_not_routed_and_sends_data( (Exception, Exception('test'),), ]) @freeze_time("2012-01-01") + @mock.patch.object(ChainlinkNodeMonitor, "_get_currency_symbol") @mock.patch.object(ChainlinkNodeMonitor, "_send_heartbeat") @mock.patch.object(ChainlinkNodeMonitor, "_get_data") def test_monitor_raises_error_if_raised_by_send_hb_and_sends_data( self, exception_class, exception_instance, mock_get_data, - mock_send_hb) -> None: + mock_send_hb, mock_get_symbol) -> None: mock_get_data.return_value = \ self.received_retrieval_info_all_source_types_enabled + mock_get_symbol.return_value = self.test_symbol expected_output_data = { 'prometheus': { 'result': { @@ -1369,17 +1380,19 @@ def test_monitor_raises_error_if_raised_by_send_hb_and_sends_data( self.test_queue_name) self.assertEqual(expected_output_data, json.loads(body)) + @mock.patch.object(ChainlinkNodeMonitor, "_get_currency_symbol") @mock.patch.object(logging.Logger, "debug") @mock.patch.object(ChainlinkNodeMonitor, "_send_heartbeat") @mock.patch.object(ChainlinkNodeMonitor, "_send_data") @mock.patch.object(ChainlinkNodeMonitor, "_get_data") def test_monitor_logs_data_if_all_sources_enabled_and_no_retrieval_error( self, mock_get_data, mock_send_data, mock_send_hb, - mock_log) -> None: + mock_log, mock_get_symbol) -> None: mock_send_data.return_value = None mock_send_hb.return_value = None mock_get_data.return_value = \ self.received_retrieval_info_all_source_types_enabled + mock_get_symbol.return_value = self.test_symbol self.test_monitor._monitor() @@ -1425,5 +1438,83 @@ def test_monitor_does_not_log_if_retrieval_error( assert_not_called_with(mock_log, self.test_monitor._display_data(processed_data)) + @freeze_time("2012-01-01") + @mock.patch.object(ChainlinkNodeMonitor, "_get_currency_symbol") + def test_process_ret_prom_data_does_not_call_get_currency_symbol_if_found( + self, mock_get_symbol) -> None: + mock_get_symbol.return_value = self.test_symbol + self.test_monitor.currency_symbol_limiter.reset() + + self.assertTrue(self.test_monitor.currency_symbol_limiter.can_do_task()) + + self.test_monitor._process_retrieved_prometheus_data( + self.retrieved_prometheus_data_example) + + self.assertFalse( + self.test_monitor.currency_symbol_limiter.can_do_task()) + self.assertEqual(self.test_monitor.currency_symbol, self.test_symbol) + + self.test_monitor._process_retrieved_prometheus_data( + self.retrieved_prometheus_data_example) + + self.assertEqual(mock_get_symbol.call_count, 1) + self.assertEqual(self.test_monitor.currency_symbol, self.test_symbol) + + @freeze_time("2012-01-01") + @mock.patch.object(ChainlinkNodeMonitor, "_get_currency_symbol") + def test_process_ret_prom_data_gets_curr_symbol_correctly_if_not_found( + self, mock_get_symbol) -> None: + mock_get_symbol.return_value = '' + self.test_monitor.currency_symbol_limiter.reset() + + self.assertTrue(self.test_monitor.currency_symbol_limiter.can_do_task()) + + self.test_monitor._process_retrieved_prometheus_data( + self.retrieved_prometheus_data_example) + + self.assertTrue( + self.test_monitor.currency_symbol_limiter.can_do_task()) + self.assertEqual(self.test_monitor.currency_symbol, '') + + mock_get_symbol.return_value = self.test_symbol + + self.test_monitor._process_retrieved_prometheus_data( + self.retrieved_prometheus_data_example) + + self.assertEqual(mock_get_symbol.call_count, 2) + self.assertFalse( + self.test_monitor.currency_symbol_limiter.can_do_task()) + self.assertEqual(self.test_monitor.currency_symbol, self.test_symbol) + + @freeze_time("2012-01-02 10:00") + @mock.patch.object(ChainlinkNodeMonitor, "_get_currency_symbol") + def test_process_ret_prom_data_calls_get_currency_symbol_if_can_do_task( + self, mock_get_symbol) -> None: + mock_get_symbol.return_value = self.test_symbol + self.test_monitor.currency_symbol_limiter.reset() + + self.assertTrue(self.test_monitor.currency_symbol_limiter.can_do_task()) + + self.test_monitor._process_retrieved_prometheus_data( + self.retrieved_prometheus_data_example) + + self.assertFalse( + self.test_monitor.currency_symbol_limiter.can_do_task()) + self.assertEqual(mock_get_symbol.call_count, 1) + self.assertEqual(self.test_monitor.currency_symbol, self.test_symbol) + + self.test_monitor.currency_symbol_limiter\ + .set_last_time_that_did_task(parser.parse("2012-01-01 10:00")) + + self.assertTrue(self.test_monitor.currency_symbol_limiter.can_do_task()) + + self.test_monitor._process_retrieved_prometheus_data( + self.retrieved_prometheus_data_example) + + self.assertFalse( + self.test_monitor.currency_symbol_limiter.can_do_task()) + self.assertEqual(mock_get_symbol.call_count, 2) + self.assertEqual(self.test_monitor.currency_symbol, self.test_symbol) + # TODO: When more sources are added we need to test for when some sources # : are enabled and some disabled diff --git a/alerter/test/monitors/node/test_cosmos.py b/alerter/test/monitors/node/test_cosmos.py index ecf7d7d10..c6a41904e 100644 --- a/alerter/test/monitors/node/test_cosmos.py +++ b/alerter/test/monitors/node/test_cosmos.py @@ -1443,7 +1443,7 @@ def test_get_tendermint_rpc_data_return_if_no_archive_source_selected( mock_select_node.return_value = {'consensus_hex_address': self.test_consensus_address, 'is_syncing': - self.test_is_syncing} + self.test_is_syncing} actual_ret = self.test_monitor._get_tendermint_rpc_data() self.assertEqual( ({}, True, NoSyncedDataSourceWasAccessibleException( diff --git a/alerter/test/test_utils/utils.py b/alerter/test/test_utils/utils.py index d82d85e82..c27c816a1 100644 --- a/alerter/test/test_utils/utils.py +++ b/alerter/test/test_utils/utils.py @@ -215,8 +215,8 @@ def save_chainlink_node_to_redis(redis: RedisApi, Keys.get_cl_node_current_gas_price_info(cl_node_id): 'None' if cl_node.current_gas_price_info is None else json.dumps( cl_node.current_gas_price_info), - Keys.get_cl_node_eth_balance_info(cl_node_id): - json.dumps(cl_node.eth_balance_info), + Keys.get_cl_node_balance_info(cl_node_id): + json.dumps(cl_node.balance_info), Keys.get_cl_node_last_prometheus_source_used(cl_node_id): str(cl_node.last_prometheus_source_used), Keys.get_cl_node_last_monitored_prometheus(cl_node_id): diff --git a/api/package-lock.json b/api/package-lock.json index 8fedc0a3b..7f49266ea 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -1,12 +1,12 @@ { "name": "panic-api", - "version": "1.1.0", + "version": "1.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "panic-api", - "version": "1.1.0", + "version": "1.1.1", "license": "MIT", "dependencies": { "cookie-parser": "^1.4.5", @@ -46,28 +46,28 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.16.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.4.tgz", - "integrity": "sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.0.tgz", + "integrity": "sha512-DGjt2QZse5SGd9nfOSqO4WLJ8NN/oHkijbXbPrxuoJO3oIPJL3TciZs9FX+cOHNiY9E9l0opL8g7BmLe3T+9ew==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.5.tgz", - "integrity": "sha512-wUcenlLzuWMZ9Zt8S0KmFwGlH6QKRh3vsm/dhDA3CHkiTA45YuG1XkHRcNRl73EFPXDp/d5kVOU0/y7x2w6OaQ==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.0.tgz", + "integrity": "sha512-mYZEvshBRHGsIAiyH5PzCFTCfbWfoYbO/jcSdXQSUQu1/pW0xDZAUP7KEc32heqWTAfAHhV9j1vH8Sav7l+JNQ==", "dev": true, "dependencies": { "@babel/code-frame": "^7.16.0", - "@babel/generator": "^7.16.5", - "@babel/helper-compilation-targets": "^7.16.3", - "@babel/helper-module-transforms": "^7.16.5", - "@babel/helpers": "^7.16.5", - "@babel/parser": "^7.16.5", + "@babel/generator": "^7.16.0", + "@babel/helper-compilation-targets": "^7.16.0", + "@babel/helper-module-transforms": "^7.16.0", + "@babel/helpers": "^7.16.0", + "@babel/parser": "^7.16.0", "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.5", + "@babel/traverse": "^7.16.0", "@babel/types": "^7.16.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", @@ -85,9 +85,9 @@ } }, "node_modules/@babel/core/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -117,9 +117,9 @@ } }, "node_modules/@babel/generator": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.5.tgz", - "integrity": "sha512-kIvCdjZqcdKqoDbVVdt5R99icaRtrtYhYK/xux5qiWCBmfdvEYMFZ68QCrpE5cbFM1JsuArUNs1ZkuKtTtUcZA==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.0.tgz", + "integrity": "sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew==", "dev": true, "dependencies": { "@babel/types": "^7.16.0", @@ -157,18 +157,6 @@ "@babel/core": "^7.0.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.5.tgz", - "integrity": "sha512-ODQyc5AnxmZWm/R2W7fzhamOk1ey8gSguo5SGvF0zcB3uUzRpTRmM/jmLSm9bDMyPlvbyJ+PwPEK0BWIoZ9wjg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-function-name": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz", @@ -207,6 +195,18 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz", + "integrity": "sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-module-imports": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz", @@ -220,18 +220,30 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.5.tgz", - "integrity": "sha512-CkvMxgV4ZyyioElFwcuWnDCcNIeyqTkCm9BxXZi73RR1ozqlpboqsbGUNvRTflgZtFbbJ1v5Emvm+lkjMYY/LQ==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz", + "integrity": "sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.16.5", "@babel/helper-module-imports": "^7.16.0", + "@babel/helper-replace-supers": "^7.16.0", "@babel/helper-simple-access": "^7.16.0", "@babel/helper-split-export-declaration": "^7.16.0", "@babel/helper-validator-identifier": "^7.15.7", "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.5", + "@babel/traverse": "^7.16.0", + "@babel/types": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz", + "integrity": "sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw==", + "dev": true, + "dependencies": { "@babel/types": "^7.16.0" }, "engines": { @@ -239,14 +251,29 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz", - "integrity": "sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz", + "integrity": "sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.16.0", + "@babel/helper-optimise-call-expression": "^7.16.0", + "@babel/traverse": "^7.16.0", + "@babel/types": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-simple-access": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz", @@ -290,13 +317,13 @@ } }, "node_modules/@babel/helpers": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.5.tgz", - "integrity": "sha512-TLgi6Lh71vvMZGEkFuIxzaPsyeYCHQ5jJOOX1f0xXn0uciFuE8cEk0wyBquMcCxBXZ5BJhE2aUB7pnWTD150Tw==", + "version": "7.16.3", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.3.tgz", + "integrity": "sha512-Xn8IhDlBPhvYTvgewPKawhADichOsbkZuzN7qz2BusOM0brChsyXMDJvldWaYMMUNiCQdQzNEioXTp3sC8Nt8w==", "dev": true, "dependencies": { "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.5", + "@babel/traverse": "^7.16.3", "@babel/types": "^7.16.0" }, "engines": { @@ -389,9 +416,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.16.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.6.tgz", - "integrity": "sha512-Gr86ujcNuPDnNOY8mi383Hvi8IYrJVJYuf3XcuBM/Dgd+bINn/7tHqsj+tKkoreMbmGsFLsltI/JJd8fOFWGDQ==", + "version": "7.16.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.3.tgz", + "integrity": "sha512-dcNwU1O4sx57ClvLBVFbEgx0UZWfd0JQX5X6fxFRCLHelFBGXFfSz6Y0FAq2PEwUqlqLkdVjVr4VASEOuUnLJw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -548,12 +575,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.5.tgz", - "integrity": "sha512-/d4//lZ1Vqb4mZ5xTep3dDK888j7BGM/iKqBmndBaoYAFPlPKrGU608VVBz5JeyAb6YQDjRu1UKqj86UhwWVgw==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.0.tgz", + "integrity": "sha512-Xv6mEXqVdaqCBfJFyeab0fH2DnUoMsDmhamxsSi4j8nLd4Vtw213WMJr55xxqipC/YVWyPY3K0blJncPYji+dQ==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.14.5" }, "engines": { "node": ">=6.9.0" @@ -577,18 +604,17 @@ } }, "node_modules/@babel/traverse": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.5.tgz", - "integrity": "sha512-FOCODAzqUMROikDYLYxl4nmwiLlu85rNqBML/A5hKRVXG2LV8d0iMqgPzdYTcIpjZEBB7D6UDU9vxRZiriASdQ==", + "version": "7.16.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.3.tgz", + "integrity": "sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag==", "dev": true, "dependencies": { "@babel/code-frame": "^7.16.0", - "@babel/generator": "^7.16.5", - "@babel/helper-environment-visitor": "^7.16.5", + "@babel/generator": "^7.16.0", "@babel/helper-function-name": "^7.16.0", "@babel/helper-hoist-variables": "^7.16.0", "@babel/helper-split-export-declaration": "^7.16.0", - "@babel/parser": "^7.16.5", + "@babel/parser": "^7.16.3", "@babel/types": "^7.16.0", "debug": "^4.1.0", "globals": "^11.1.0" @@ -598,9 +624,9 @@ } }, "node_modules/@babel/traverse/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -686,16 +712,16 @@ } }, "node_modules/@jest/console": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.4.2.tgz", - "integrity": "sha512-xknHThRsPB/To1FUbi6pCe43y58qFC03zfb6R7fDb/FfC7k2R3i1l+izRBJf8DI46KhYGRaF14Eo9A3qbBoixg==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.3.1.tgz", + "integrity": "sha512-RkFNWmv0iui+qsOr/29q9dyfKTTT5DCuP31kUwg7rmOKPT/ozLeGLKJKVIiOfbiKyleUZKIrHwhmiZWVe8IMdw==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^27.4.2", - "jest-util": "^27.4.2", + "jest-message-util": "^27.3.1", + "jest-util": "^27.3.1", "slash": "^3.0.0" }, "engines": { @@ -703,35 +729,35 @@ } }, "node_modules/@jest/core": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.4.5.tgz", - "integrity": "sha512-3tm/Pevmi8bDsgvo73nX8p/WPng6KWlCyScW10FPEoN1HU4pwI83tJ3TsFvi1FfzsjwUlMNEPowgb/rPau/LTQ==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.3.1.tgz", + "integrity": "sha512-DMNE90RR5QKx0EA+wqe3/TNEwiRpOkhshKNxtLxd4rt3IZpCt+RSL+FoJsGeblRZmqdK4upHA/mKKGPPRAifhg==", "dev": true, "dependencies": { - "@jest/console": "^27.4.2", - "@jest/reporters": "^27.4.5", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", + "@jest/console": "^27.3.1", + "@jest/reporters": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.8.1", "exit": "^0.1.2", "graceful-fs": "^4.2.4", - "jest-changed-files": "^27.4.2", - "jest-config": "^27.4.5", - "jest-haste-map": "^27.4.5", - "jest-message-util": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.5", - "jest-resolve-dependencies": "^27.4.5", - "jest-runner": "^27.4.5", - "jest-runtime": "^27.4.5", - "jest-snapshot": "^27.4.5", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", - "jest-watcher": "^27.4.2", + "jest-changed-files": "^27.3.0", + "jest-config": "^27.3.1", + "jest-haste-map": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.3.1", + "jest-resolve-dependencies": "^27.3.1", + "jest-runner": "^27.3.1", + "jest-runtime": "^27.3.1", + "jest-snapshot": "^27.3.1", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", + "jest-watcher": "^27.3.1", "micromatch": "^4.0.4", "rimraf": "^3.0.0", "slash": "^3.0.0", @@ -749,63 +775,103 @@ } } }, + "node_modules/@jest/core/node_modules/jest-config": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.3.1.tgz", + "integrity": "sha512-KY8xOIbIACZ/vdYCKSopL44I0xboxC751IX+DXL2+Wx6DKNycyEfV3rryC3BPm5Uq/BBqDoMrKuqLEUNJmMKKg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^27.3.1", + "@jest/types": "^27.2.5", + "babel-jest": "^27.3.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.4", + "jest-circus": "^27.3.1", + "jest-environment-jsdom": "^27.3.1", + "jest-environment-node": "^27.3.1", + "jest-get-type": "^27.3.1", + "jest-jasmine2": "^27.3.1", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.3.1", + "jest-runner": "^27.3.1", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", + "micromatch": "^4.0.4", + "pretty-format": "^27.3.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } + } + }, "node_modules/@jest/environment": { - "version": "27.4.4", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.4.4.tgz", - "integrity": "sha512-q+niMx7cJgt/t/b6dzLOh4W8Ef/8VyKG7hxASK39jakijJzbFBGpptx3RXz13FFV7OishQ9lTbv+dQ5K3EhfDQ==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.3.1.tgz", + "integrity": "sha512-BCKCj4mOVLme6Tanoyc9k0ultp3pnmuyHw73UHRPeeZxirsU/7E3HC4le/VDb/SMzE1JcPnto+XBKFOcoiJzVw==", "dev": true, "dependencies": { - "@jest/fake-timers": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/fake-timers": "^27.3.1", + "@jest/types": "^27.2.5", "@types/node": "*", - "jest-mock": "^27.4.2" + "jest-mock": "^27.3.0" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/fake-timers": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.4.2.tgz", - "integrity": "sha512-f/Xpzn5YQk5adtqBgvw1V6bF8Nx3hY0OIRRpCvWcfPl0EAjdqWPdhH3t/3XpiWZqtjIEHDyMKP9ajpva1l4Zmg==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.3.1.tgz", + "integrity": "sha512-M3ZFgwwlqJtWZ+QkBG5NmC23A9w+A6ZxNsO5nJxJsKYt4yguBd3i8TpjQz5NfCX91nEve1KqD9RA2Q+Q1uWqoA==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "@sinonjs/fake-timers": "^8.0.1", "@types/node": "*", - "jest-message-util": "^27.4.2", - "jest-mock": "^27.4.2", - "jest-util": "^27.4.2" + "jest-message-util": "^27.3.1", + "jest-mock": "^27.3.0", + "jest-util": "^27.3.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/globals": { - "version": "27.4.4", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.4.4.tgz", - "integrity": "sha512-bqpqQhW30BOreXM8bA8t8JbOQzsq/WnPTnBl+It3UxAD9J8yxEAaBEylHx1dtBapAr/UBk8GidXbzmqnee8tYQ==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.3.1.tgz", + "integrity": "sha512-Q651FWiWQAIFiN+zS51xqhdZ8g9b88nGCobC87argAxA7nMfNQq0Q0i9zTfQYgLa6qFXk2cGANEqfK051CZ8Pg==", "dev": true, "dependencies": { - "@jest/environment": "^27.4.4", - "@jest/types": "^27.4.2", - "expect": "^27.4.2" + "@jest/environment": "^27.3.1", + "@jest/types": "^27.2.5", + "expect": "^27.3.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/reporters": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.4.5.tgz", - "integrity": "sha512-3orsG4vi8zXuBqEoy2LbnC1kuvkg1KQUgqNxmxpQgIOQEPeV0onvZu+qDQnEoX8qTQErtqn/xzcnbpeTuOLSiA==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.3.1.tgz", + "integrity": "sha512-m2YxPmL9Qn1emFVgZGEiMwDntDxRRQ2D58tiDQlwYTg5GvbFOKseYCcHtn0WsI8CG4vzPglo3nqbOiT8ySBT/w==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.4.2", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", + "@jest/console": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", @@ -817,10 +883,10 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.0.2", - "jest-haste-map": "^27.4.5", - "jest-resolve": "^27.4.5", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.5", + "jest-haste-map": "^27.3.1", + "jest-resolve": "^27.3.1", + "jest-util": "^27.3.1", + "jest-worker": "^27.3.1", "slash": "^3.0.0", "source-map": "^0.6.0", "string-length": "^4.0.1", @@ -840,9 +906,9 @@ } }, "node_modules/@jest/source-map": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.4.0.tgz", - "integrity": "sha512-Ntjx9jzP26Bvhbm93z/AKcPRj/9wrkI88/gK60glXDx1q+IeI0rf7Lw2c89Ch6ofonB0On/iRDreQuQ6te9pgQ==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.0.6.tgz", + "integrity": "sha512-Fek4mi5KQrqmlY07T23JRi0e7Z9bXTOOD86V/uS0EIW4PClvPDqZOyFlLpNJheS6QI0FNX1CgmPjtJ4EA/2M+g==", "dev": true, "dependencies": { "callsites": "^3.0.0", @@ -854,13 +920,13 @@ } }, "node_modules/@jest/test-result": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.4.2.tgz", - "integrity": "sha512-kr+bCrra9jfTgxHXHa2UwoQjxvQk3Am6QbpAiJ5x/50LW8llOYrxILkqY0lZRW/hu8FXesnudbql263+EW9iNA==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.3.1.tgz", + "integrity": "sha512-mLn6Thm+w2yl0opM8J/QnPTqrfS4FoXsXF2WIWJb2O/GBSyResL71BRuMYbYRsGt7ELwS5JGcEcGb52BNrumgg==", "dev": true, "dependencies": { - "@jest/console": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/console": "^27.3.1", + "@jest/types": "^27.2.5", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" }, @@ -869,36 +935,36 @@ } }, "node_modules/@jest/test-sequencer": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.4.5.tgz", - "integrity": "sha512-n5woIn/1v+FT+9hniymHPARA9upYUmfi5Pw9ewVwXCDlK4F5/Gkees9v8vdjGdAIJ2MPHLHodiajLpZZanWzEQ==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.3.1.tgz", + "integrity": "sha512-siySLo07IMEdSjA4fqEnxfIX8lB/lWYsBPwNFtkOvsFQvmBrL3yj3k3uFNZv/JDyApTakRpxbKLJ3CT8UGVCrA==", "dev": true, "dependencies": { - "@jest/test-result": "^27.4.2", + "@jest/test-result": "^27.3.1", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.5", - "jest-runtime": "^27.4.5" + "jest-haste-map": "^27.3.1", + "jest-runtime": "^27.3.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/@jest/transform": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.4.5.tgz", - "integrity": "sha512-PuMet2UlZtlGzwc6L+aZmR3I7CEBpqadO03pU40l2RNY2fFJ191b9/ITB44LNOhVtsyykx0OZvj0PCyuLm7Eew==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.3.1.tgz", + "integrity": "sha512-3fSvQ02kuvjOI1C1ssqMVBKJpZf6nwoCiSu00zAKh5nrp3SptNtZy/8s5deayHnqxhjD9CWDJ+yqQwuQ0ZafXQ==", "dev": true, "dependencies": { "@babel/core": "^7.1.0", - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "babel-plugin-istanbul": "^6.0.0", "chalk": "^4.0.0", "convert-source-map": "^1.4.0", "fast-json-stable-stringify": "^2.0.0", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.5", - "jest-regex-util": "^27.4.0", - "jest-util": "^27.4.2", + "jest-haste-map": "^27.3.1", + "jest-regex-util": "^27.0.6", + "jest-util": "^27.3.1", "micromatch": "^4.0.4", "pirates": "^4.0.1", "slash": "^3.0.0", @@ -910,9 +976,9 @@ } }, "node_modules/@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.2.5.tgz", + "integrity": "sha512-nmuM4VuDtCZcY+eTpw+0nvstwReMsjPoj7ZR80/BbixulhLaiX+fbv8oeLW8WZlJMcsGQsTmMKT/iTZu1Uy/lQ==", "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "^2.0.0", @@ -977,9 +1043,9 @@ "dev": true }, "node_modules/@types/babel__core": { - "version": "7.1.17", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.17.tgz", - "integrity": "sha512-6zzkezS9QEIL8yCBvXWxPTJPNuMeECJVxSOhxNY/jfq9LxOTHivaYTqr37n9LknWWRTIkzqH2UilS5QFvfa90A==", + "version": "7.1.16", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz", + "integrity": "sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ==", "dev": true, "dependencies": { "@babel/parser": "^7.1.0", @@ -1018,9 +1084,9 @@ } }, "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==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", "dev": true, "dependencies": { "@types/connect": "*", @@ -1028,19 +1094,18 @@ } }, "node_modules/@types/bson": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.2.0.tgz", - "integrity": "sha512-ELCPqAdroMdcuxqwMgUpifQyRoTpyYCNr1V9xKyF40VsBobsj+BbWNRvwGchMgBPGqkw655ypkjj2MEF5ywVwg==", - "deprecated": "This is a stub types definition. bson provides its own type definitions, so you do not need this installed.", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.3.tgz", + "integrity": "sha512-mVRvYnTOZJz3ccpxhr3wgxVmSeiYinW+zlzQz3SXWaJmD1DuL05Jeq7nKw3SnbKmbleW5qrLG5vdyWe/A9sXhw==", "dev": true, "dependencies": { - "bson": "*" + "@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==", + "version": "3.4.34", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", + "integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==", "dev": true, "dependencies": { "@types/node": "*" @@ -1068,9 +1133,9 @@ "dev": true }, "node_modules/@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.12.tgz", + "integrity": "sha512-pTYas6FrP15B1Oa0bkN5tQMNqOcVXa9j4FTFtO8DWI9kppKib+6NJtfTOOLcwxuuYvcX2+dVG6et1SxW/Kc17Q==", "dev": true, "dependencies": { "@types/body-parser": "*", @@ -1080,9 +1145,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.26", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.26.tgz", - "integrity": "sha512-zeu3tpouA043RHxW0gzRxwCHchMgftE8GArRsvYT0ByDMbn19olQHx5jLue0LxWY6iYtXb7rXmuVtSkhy9YZvQ==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.21.tgz", + "integrity": "sha512-gwCiEZqW6f7EoR8TTEfalyEhb1zA5jQJnRngr97+3pzMaO1RKoI1w2bw07TK72renMUVWcWS5mLI6rk1NqN0nA==", "dev": true, "dependencies": { "@types/node": "*", @@ -1124,9 +1189,9 @@ } }, "node_modules/@types/jest": { - "version": "27.0.3", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.3.tgz", - "integrity": "sha512-cmmwv9t7gBYt7hNKH5Spu7Kuu/DotGa+Ff+JGRKZ4db5eh8PnKS4LuebJ3YLUoyOyIHraTGyULn23YtEAm0VSg==", + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.2.tgz", + "integrity": "sha512-4dRxkS/AFX0c5XW6IPMNOydLn2tEhNhJV7DnYK+0bjoJZ+QTmfucBlihX7aoEsh/ocYtkLC73UbnBXBXIxsULA==", "dev": true, "dependencies": { "jest-diff": "^27.0.0", @@ -1140,9 +1205,9 @@ "dev": true }, "node_modules/@types/mongodb": { - "version": "3.6.20", - "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.20.tgz", - "integrity": "sha512-WcdpPJCakFzcWWD9juKoZbRtQxKIMYF/JIAM4JrNHrMcnJL6/a2NWjXxW7fo9hxboxxkg+icff8d7+WIEvKgYQ==", + "version": "3.6.17", + "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.17.tgz", + "integrity": "sha512-9hhgvYPdC5iHyyksPcKCu45gfaAIPQHKHGdvNXu4582DmOZX3wrUJIJPT40o4G1oTKPgpMMFqZglOTjhnYoF+A==", "dev": true, "dependencies": { "@types/bson": "*", @@ -1150,42 +1215,42 @@ } }, "node_modules/@types/node": { - "version": "15.14.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.14.9.tgz", - "integrity": "sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A==", + "version": "15.12.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz", + "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==", "dev": true }, "node_modules/@types/prettier": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.2.tgz", - "integrity": "sha512-ekoj4qOQYp7CvjX8ZDBgN86w3MqQhLE1hczEJbEIjgFEumDy+na/4AJAbLXfgEWFNB2pKadM5rPFtuSGMWK7xA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.1.tgz", + "integrity": "sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==", "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==", + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==", "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==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", "dev": true }, "node_modules/@types/redis": { - "version": "2.8.32", - "resolved": "https://registry.npmjs.org/@types/redis/-/redis-2.8.32.tgz", - "integrity": "sha512-7jkMKxcGq9p242exlbsVzuJb57KqHRhNl4dHoQu2Y5v9bCAbtIXXH0R3HleSQW4CTOqpHIYUW3t6tpUj4BVQ+w==", + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/@types/redis/-/redis-2.8.29.tgz", + "integrity": "sha512-/pjQ9lwnL/t1bEfRHQFEJB3kHCR65tpB19NEWmbqcgGgqrfeGo/9b4tUtHbClxQoy3+g6Esx2QRtV7fk7kBPYg==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "version": "1.13.9", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz", + "integrity": "sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==", "dev": true, "dependencies": { "@types/mime": "^1", @@ -1251,9 +1316,9 @@ } }, "node_modules/acorn": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", - "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1306,9 +1371,9 @@ } }, "node_modules/agent-base/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -1407,16 +1472,16 @@ "dev": true }, "node_modules/babel-jest": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.4.5.tgz", - "integrity": "sha512-3uuUTjXbgtODmSv/DXO9nZfD52IyC2OYTFaXGRzL0kpykzroaquCrD5+lZNafTvZlnNqZHt5pb0M08qVBZnsnA==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.3.1.tgz", + "integrity": "sha512-SjIF8hh/ir0peae2D6S6ZKRhUy7q/DnpH7k/V6fT4Bgs/LXXUztOpX4G2tCgq8mLo5HA9mN6NmlFMeYtKmIsTQ==", "dev": true, "dependencies": { - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^27.4.0", + "babel-preset-jest": "^27.2.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", "slash": "^3.0.0" @@ -1461,9 +1526,9 @@ } }, "node_modules/babel-plugin-jest-hoist": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz", - "integrity": "sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.2.0.tgz", + "integrity": "sha512-TOux9khNKdi64mW+0OIhcmbAn75tTlzKhxmiNXevQaPbrBYK7YKjP1jl6NHTJ6XR5UgUrJbCnWlKVnJn29dfjw==", "dev": true, "dependencies": { "@babel/template": "^7.3.3", @@ -1499,12 +1564,12 @@ } }, "node_modules/babel-preset-jest": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.4.0.tgz", - "integrity": "sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.2.0.tgz", + "integrity": "sha512-z7MgQ3peBwN5L5aCqBKnF6iqdlvZvFUQynEhu0J+X9nHLU72jO3iY331lcYrg+AssJ8q7xsv5/3AICzVmJ/wvg==", "dev": true, "dependencies": { - "babel-plugin-jest-hoist": "^27.4.0", + "babel-plugin-jest-hoist": "^27.2.0", "babel-preset-current-node-syntax": "^1.0.0" }, "engines": { @@ -1520,26 +1585,6 @@ "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/bl": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", @@ -1598,13 +1643,13 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", - "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "version": "4.17.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.6.tgz", + "integrity": "sha512-uPgz3vyRTlEiCv4ee9KlsKgo2V6qPk7Jsn0KAn2OBqbqKo3iNcPEC1Ti6J4dwnz+aIRfEEEuOzC9IBk8tXUomw==", "dev": true, "dependencies": { - "caniuse-lite": "^1.0.30001286", - "electron-to-chromium": "^1.4.17", + "caniuse-lite": "^1.0.30001274", + "electron-to-chromium": "^1.3.886", "escalade": "^3.1.1", "node-releases": "^2.0.1", "picocolors": "^1.0.0" @@ -1642,39 +1687,11 @@ } }, "node_modules/bson": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.0.tgz", - "integrity": "sha512-8jw1NU1hglS+Da1jDOUYuNcBJ4cNHCFIqzlwoFNnsTOg2R/ox0aTYcTiBN4dzRa9q7Cvy6XErh3L8ReTEb9AQQ==", - "dev": true, - "dependencies": { - "buffer": "^5.6.0" - }, + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", + "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==", "engines": { - "node": ">=6.9.0" - } - }, - "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": ">=0.6.19" } }, "node_modules/buffer-from": { @@ -1723,9 +1740,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001287", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001287.tgz", - "integrity": "sha512-4udbs9bc0hfNrcje++AxBuc6PfLNHwh3PO9kbwnfCQWyqtlzg3py0YgFu8jyRTTo85VAz4U+VLxSlID09vNtWA==", + "version": "1.0.30001279", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001279.tgz", + "integrity": "sha512-VfEHpzHEXj6/CxggTwSFoZBBYGQfQv9Cf42KPlO79sWXCD1QNKWKsKzFeWL7QpZHJQYAvocqV6Rty1yJMkqWLQ==", "dev": true, "funding": { "type": "opencollective", @@ -1758,9 +1775,9 @@ } }, "node_modules/ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", "dev": true }, "node_modules/cjs-module-lexer": { @@ -1867,19 +1884,19 @@ } }, "node_modules/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-parser": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", - "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz", + "integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==", "dependencies": { - "cookie": "0.4.1", + "cookie": "0.4.0", "cookie-signature": "1.0.6" }, "engines": { @@ -1898,9 +1915,9 @@ "dev": true }, "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==" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "node_modules/cors": { "version": "2.8.5", @@ -2017,9 +2034,9 @@ } }, "node_modules/denque": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", - "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz", + "integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==", "engines": { "node": ">=0.10" } @@ -2056,9 +2073,9 @@ } }, "node_modules/diff-sequences": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.4.0.tgz", - "integrity": "sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", + "integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==", "dev": true, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -2099,9 +2116,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "node_modules/electron-to-chromium": { - "version": "1.4.20", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.20.tgz", - "integrity": "sha512-N7ZVNrdzX8NE90OXEFBMsBf3fp8P/vVDUER3WCUZjzC7OkNTXHVoF6W9qVhq8+dA8tGnbDajzUpj2ISNVVyj+Q==", + "version": "1.3.894", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.894.tgz", + "integrity": "sha512-WY8pA4irAZ4cm/Pr7YFPtPLVqj3nU6d0SbfoHF6M7HZNONfPdAnYAarumqQ75go2LuN72uO9wGuCEqnfya/ytg==", "dev": true }, "node_modules/emittery": { @@ -2247,17 +2264,17 @@ } }, "node_modules/expect": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.4.2.tgz", - "integrity": "sha512-BjAXIDC6ZOW+WBFNg96J22D27Nq5ohn+oGcuP2rtOtcjuxNoV9McpQ60PcQWhdFOSBIQdR72e+4HdnbZTFSTyg==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.3.1.tgz", + "integrity": "sha512-MrNXV2sL9iDRebWPGOGFdPQRl2eDQNu/uhxIMShjjx74T6kC6jFIkmQ6OqXDtevjGUkyB2IT56RzDBqXf/QPCg==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "ansi-styles": "^5.0.0", - "jest-get-type": "^27.4.0", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-regex-util": "^27.4.0" + "jest-get-type": "^27.3.1", + "jest-matcher-utils": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-regex-util": "^27.0.6" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -2315,14 +2332,6 @@ "node": ">= 0.10.0" } }, - "node_modules/express/node_modules/cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", - "engines": { - "node": ">= 0.6" - } - }, "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", @@ -2627,9 +2636,9 @@ } }, "node_modules/http-proxy-agent/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -2663,9 +2672,9 @@ } }, "node_modules/https-proxy-agent/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -2705,26 +2714,6 @@ "node": ">=0.10.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/import-local": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", @@ -2900,9 +2889,9 @@ } }, "node_modules/istanbul-lib-source-maps/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -2923,9 +2912,9 @@ "dev": true }, "node_modules/istanbul-reports": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.1.tgz", - "integrity": "sha512-q1kvhAXWSsXfMjCdNHNPKZZv94OlspKnoGv+R9RGbnqOOQ0VbNfLFgQDVgi7hHenKsndGq3/o0OBdzDXthWcNw==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.5.tgz", + "integrity": "sha512-5+19PlhnGabNWB7kOFnuxT8H3T/iIyQzIbQMxXsURmmvKg86P2sbkrGOT77VnHw0Qr0gc2XzRaRfMZYYbSQCJQ==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -2936,14 +2925,14 @@ } }, "node_modules/jest": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.4.5.tgz", - "integrity": "sha512-uT5MiVN3Jppt314kidCk47MYIRilJjA/l2mxwiuzzxGUeJIvA8/pDaJOAX5KWvjAo7SCydcW0/4WEtgbLMiJkg==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.3.1.tgz", + "integrity": "sha512-U2AX0AgQGd5EzMsiZpYt8HyZ+nSVIh5ujQ9CPp9EQZJMjXIiSZpJNweZl0swatKRoqHWgGKM3zaSwm4Zaz87ng==", "dev": true, "dependencies": { - "@jest/core": "^27.4.5", + "@jest/core": "^27.3.1", "import-local": "^3.0.2", - "jest-cli": "^27.4.5" + "jest-cli": "^27.3.1" }, "bin": { "jest": "bin/jest.js" @@ -2961,12 +2950,12 @@ } }, "node_modules/jest-changed-files": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.4.2.tgz", - "integrity": "sha512-/9x8MjekuzUQoPjDHbBiXbNEBauhrPU2ct7m8TfCg69ywt1y/N+yYwGh3gCpnqUS3klYWDU/lSNgv+JhoD2k1A==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.3.0.tgz", + "integrity": "sha512-9DJs9garMHv4RhylUMZgbdCJ3+jHSkpL9aaVKp13xtXAD80qLTLrqcDZL1PHA9dYA0bCI86Nv2BhkLpLhrBcPg==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "execa": "^5.0.0", "throat": "^6.0.1" }, @@ -2975,27 +2964,27 @@ } }, "node_modules/jest-circus": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.4.5.tgz", - "integrity": "sha512-eTNWa9wsvBwPykhMMShheafbwyakcdHZaEYh5iRrQ0PFJxkDP/e3U/FvzGuKWu2WpwUA3C3hPlfpuzvOdTVqnw==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.3.1.tgz", + "integrity": "sha512-v1dsM9II6gvXokgqq6Yh2jHCpfg7ZqV4jWY66u7npz24JnhP3NHxI0sKT7+ZMQ7IrOWHYAaeEllOySbDbWsiXw==", "dev": true, "dependencies": { - "@jest/environment": "^27.4.4", - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/environment": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/types": "^27.2.5", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", - "expect": "^27.4.2", + "expect": "^27.3.1", "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.2", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-runtime": "^27.4.5", - "jest-snapshot": "^27.4.5", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.2", + "jest-each": "^27.3.1", + "jest-matcher-utils": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-runtime": "^27.3.1", + "jest-snapshot": "^27.3.1", + "jest-util": "^27.3.1", + "pretty-format": "^27.3.1", "slash": "^3.0.0", "stack-utils": "^2.0.3", "throat": "^6.0.1" @@ -3005,21 +2994,21 @@ } }, "node_modules/jest-cli": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.4.5.tgz", - "integrity": "sha512-hrky3DSgE0u7sQxaCL7bdebEPHx5QzYmrGuUjaPLmPE8jx5adtvGuOlRspvMoVLTTDOHRnZDoRLYJuA+VCI7Hg==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.3.1.tgz", + "integrity": "sha512-WHnCqpfK+6EvT62me6WVs8NhtbjAS4/6vZJnk7/2+oOr50cwAzG4Wxt6RXX0hu6m1169ZGMlhYYUNeKBXCph/Q==", "dev": true, "dependencies": { - "@jest/core": "^27.4.5", - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/core": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/types": "^27.2.5", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.4", "import-local": "^3.0.2", - "jest-config": "^27.4.5", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", + "jest-config": "^27.3.1", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", "prompts": "^2.0.1", "yargs": "^16.2.0" }, @@ -3038,34 +3027,33 @@ } } }, - "node_modules/jest-config": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.4.5.tgz", - "integrity": "sha512-t+STVJtPt+fpqQ8GBw850NtSQbnDOw/UzdPfzDaHQ48/AylQlW7LHj3dH+ndxhC1UxJ0Q3qkq7IH+nM1skwTwA==", + "node_modules/jest-cli/node_modules/jest-config": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.3.1.tgz", + "integrity": "sha512-KY8xOIbIACZ/vdYCKSopL44I0xboxC751IX+DXL2+Wx6DKNycyEfV3rryC3BPm5Uq/BBqDoMrKuqLEUNJmMKKg==", "dev": true, "dependencies": { "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^27.4.5", - "@jest/types": "^27.4.2", - "babel-jest": "^27.4.5", + "@jest/test-sequencer": "^27.3.1", + "@jest/types": "^27.2.5", + "babel-jest": "^27.3.1", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", "glob": "^7.1.1", "graceful-fs": "^4.2.4", - "jest-circus": "^27.4.5", - "jest-environment-jsdom": "^27.4.4", - "jest-environment-node": "^27.4.4", - "jest-get-type": "^27.4.0", - "jest-jasmine2": "^27.4.5", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.5", - "jest-runner": "^27.4.5", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", + "jest-circus": "^27.3.1", + "jest-environment-jsdom": "^27.3.1", + "jest-environment-node": "^27.3.1", + "jest-get-type": "^27.3.1", + "jest-jasmine2": "^27.3.1", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.3.1", + "jest-runner": "^27.3.1", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", "micromatch": "^4.0.4", - "pretty-format": "^27.4.2", - "slash": "^3.0.0" + "pretty-format": "^27.3.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" @@ -3080,24 +3068,24 @@ } }, "node_modules/jest-diff": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.4.2.tgz", - "integrity": "sha512-ujc9ToyUZDh9KcqvQDkk/gkbf6zSaeEg9AiBxtttXW59H/AcqEYp1ciXAtJp+jXWva5nAf/ePtSsgWwE5mqp4Q==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.3.1.tgz", + "integrity": "sha512-PCeuAH4AWUo2O5+ksW4pL9v5xJAcIKPUPfIhZBcG1RKv/0+dvaWTQK1Nrau8d67dp65fOqbeMdoil+6PedyEPQ==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "diff-sequences": "^27.4.0", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.2" + "diff-sequences": "^27.0.6", + "jest-get-type": "^27.3.1", + "pretty-format": "^27.3.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-docblock": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.4.0.tgz", - "integrity": "sha512-7TBazUdCKGV7svZ+gh7C8esAnweJoG+SvcF6Cjqj4l17zA2q1cMwx2JObSioubk317H+cjcHgP+7fTs60paulg==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.0.6.tgz", + "integrity": "sha512-Fid6dPcjwepTFraz0YxIMCi7dejjJ/KL9FBjPYhBp4Sv1Y9PdhImlKZqYU555BlN4TQKaTc+F2Av1z+anVyGkA==", "dev": true, "dependencies": { "detect-newline": "^3.0.0" @@ -3107,33 +3095,33 @@ } }, "node_modules/jest-each": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.4.2.tgz", - "integrity": "sha512-53V2MNyW28CTruB3lXaHNk6PkiIFuzdOC9gR3C6j8YE/ACfrPnz+slB0s17AgU1TtxNzLuHyvNlLJ+8QYw9nBg==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.3.1.tgz", + "integrity": "sha512-E4SwfzKJWYcvOYCjOxhZcxwL+AY0uFMvdCOwvzgutJiaiodFjkxQQDxHm8FQBeTqDnSmKsQWn7ldMRzTn2zJaQ==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.2" + "jest-get-type": "^27.3.1", + "jest-util": "^27.3.1", + "pretty-format": "^27.3.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-environment-jsdom": { - "version": "27.4.4", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.4.4.tgz", - "integrity": "sha512-cYR3ndNfHBqQgFvS1RL7dNqSvD//K56j/q1s2ygNHcfTCAp12zfIromO1w3COmXrxS8hWAh7+CmZmGCIoqGcGA==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.3.1.tgz", + "integrity": "sha512-3MOy8qMzIkQlfb3W1TfrD7uZHj+xx8Olix5vMENkj5djPmRqndMaXtpnaZkxmxM+Qc3lo+yVzJjzuXbCcZjAlg==", "dev": true, "dependencies": { - "@jest/environment": "^27.4.4", - "@jest/fake-timers": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/environment": "^27.3.1", + "@jest/fake-timers": "^27.3.1", + "@jest/types": "^27.2.5", "@types/node": "*", - "jest-mock": "^27.4.2", - "jest-util": "^27.4.2", + "jest-mock": "^27.3.0", + "jest-util": "^27.3.1", "jsdom": "^16.6.0" }, "engines": { @@ -3141,47 +3129,47 @@ } }, "node_modules/jest-environment-node": { - "version": "27.4.4", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.4.4.tgz", - "integrity": "sha512-D+v3lbJ2GjQTQR23TK0kY3vFVmSeea05giInI41HHOaJnAwOnmUHTZgUaZL+VxUB43pIzoa7PMwWtCVlIUoVoA==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.3.1.tgz", + "integrity": "sha512-T89F/FgkE8waqrTSA7/ydMkcc52uYPgZZ6q8OaZgyiZkJb5QNNCF6oPZjH9IfPFfcc9uBWh1574N0kY0pSvTXw==", "dev": true, "dependencies": { - "@jest/environment": "^27.4.4", - "@jest/fake-timers": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/environment": "^27.3.1", + "@jest/fake-timers": "^27.3.1", + "@jest/types": "^27.2.5", "@types/node": "*", - "jest-mock": "^27.4.2", - "jest-util": "^27.4.2" + "jest-mock": "^27.3.0", + "jest-util": "^27.3.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.3.1.tgz", + "integrity": "sha512-+Ilqi8hgHSAdhlQ3s12CAVNd8H96ZkQBfYoXmArzZnOfAtVAJEiPDBirjByEblvG/4LPJmkL+nBqPO3A1YJAEg==", "dev": true, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-haste-map": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.4.5.tgz", - "integrity": "sha512-oJm1b5qhhPs78K24EDGifWS0dELYxnoBiDhatT/FThgB9yxqUm5F6li3Pv+Q+apMBmmPNzOBnZ7ZxWMB1Leq1Q==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.3.1.tgz", + "integrity": "sha512-lYfNZIzwPccDJZIyk9Iz5iQMM/MH56NIIcGj7AFU1YyA4ewWFBl8z+YPJuSCRML/ee2cCt2y3W4K3VXPT6Nhzg==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "@types/graceful-fs": "^4.1.2", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "graceful-fs": "^4.2.4", - "jest-regex-util": "^27.4.0", - "jest-serializer": "^27.4.0", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.5", + "jest-regex-util": "^27.0.6", + "jest-serializer": "^27.0.6", + "jest-util": "^27.3.1", + "jest-worker": "^27.3.1", "micromatch": "^4.0.4", "walker": "^1.0.7" }, @@ -3193,28 +3181,28 @@ } }, "node_modules/jest-jasmine2": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.4.5.tgz", - "integrity": "sha512-oUnvwhJDj2LhOiUB1kdnJjkx8C5PwgUZQb9urF77mELH9DGR4e2GqpWQKBOYXWs5+uTN9BGDqRz3Aeg5Wts7aw==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.3.1.tgz", + "integrity": "sha512-WK11ZUetDQaC09w4/j7o4FZDUIp+4iYWH/Lik34Pv7ukL+DuXFGdnmmi7dT58J2ZYKFB5r13GyE0z3NPeyJmsg==", "dev": true, "dependencies": { "@babel/traverse": "^7.1.0", - "@jest/environment": "^27.4.4", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/environment": "^27.3.1", + "@jest/source-map": "^27.0.6", + "@jest/test-result": "^27.3.1", + "@jest/types": "^27.2.5", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", - "expect": "^27.4.2", + "expect": "^27.3.1", "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.2", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-runtime": "^27.4.5", - "jest-snapshot": "^27.4.5", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.2", + "jest-each": "^27.3.1", + "jest-matcher-utils": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-runtime": "^27.3.1", + "jest-snapshot": "^27.3.1", + "jest-util": "^27.3.1", + "pretty-format": "^27.3.1", "throat": "^6.0.1" }, "engines": { @@ -3222,46 +3210,46 @@ } }, "node_modules/jest-leak-detector": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.4.2.tgz", - "integrity": "sha512-ml0KvFYZllzPBJWDei3mDzUhyp/M4ubKebX++fPaudpe8OsxUE+m+P6ciVLboQsrzOCWDjE20/eXew9QMx/VGw==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.3.1.tgz", + "integrity": "sha512-78QstU9tXbaHzwlRlKmTpjP9k4Pvre5l0r8Spo4SbFFVy/4Abg9I6ZjHwjg2QyKEAMg020XcjP+UgLZIY50yEg==", "dev": true, "dependencies": { - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.2" + "jest-get-type": "^27.3.1", + "pretty-format": "^27.3.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-matcher-utils": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.4.2.tgz", - "integrity": "sha512-jyP28er3RRtMv+fmYC/PKG8wvAmfGcSNproVTW2Y0P/OY7/hWUOmsPfxN1jOhM+0u2xU984u2yEagGivz9OBGQ==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.3.1.tgz", + "integrity": "sha512-hX8N7zXS4k+8bC1Aj0OWpGb7D3gIXxYvPNK1inP5xvE4ztbz3rc4AkI6jGVaerepBnfWB17FL5lWFJT3s7qo8w==", "dev": true, "dependencies": { "chalk": "^4.0.0", - "jest-diff": "^27.4.2", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.2" + "jest-diff": "^27.3.1", + "jest-get-type": "^27.3.1", + "pretty-format": "^27.3.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-message-util": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.4.2.tgz", - "integrity": "sha512-OMRqRNd9E0DkBLZpFtZkAGYOXl6ZpoMtQJWTAREJKDOFa0M6ptB7L67tp+cszMBkvSgKOhNtQp2Vbcz3ZZKo/w==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.3.1.tgz", + "integrity": "sha512-bh3JEmxsTZ/9rTm0jQrPElbY2+y48Rw2t47uMfByNyUVR+OfPh4anuyKsGqsNkXk/TI4JbLRZx+7p7Hdt6q1yg==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", "micromatch": "^4.0.4", - "pretty-format": "^27.4.2", + "pretty-format": "^27.3.1", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, @@ -3270,12 +3258,12 @@ } }, "node_modules/jest-mock": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.4.2.tgz", - "integrity": "sha512-PDDPuyhoukk20JrQKeofK12hqtSka7mWH0QQuxSNgrdiPsrnYYLS6wbzu/HDlxZRzji5ylLRULeuI/vmZZDrYA==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.3.0.tgz", + "integrity": "sha512-ziZiLk0elZOQjD08bLkegBzv5hCABu/c8Ytx45nJKkysQwGaonvmTxwjLqEA4qGdasq9o2I8/HtdGMNnVsMTGw==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "@types/node": "*" }, "engines": { @@ -3300,27 +3288,27 @@ } }, "node_modules/jest-regex-util": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.4.0.tgz", - "integrity": "sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.0.6.tgz", + "integrity": "sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ==", "dev": true, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-resolve": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.4.5.tgz", - "integrity": "sha512-xU3z1BuOz/hUhVUL+918KqUgK+skqOuUsAi7A+iwoUldK6/+PW+utK8l8cxIWT9AW7IAhGNXjSAh1UYmjULZZw==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.3.1.tgz", + "integrity": "sha512-Dfzt25CFSPo3Y3GCbxynRBZzxq9AdyNN+x/v2IqYx6KVT5Z6me2Z/PsSGFSv3cOSUZqJ9pHxilao/I/m9FouLw==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.5", + "jest-haste-map": "^27.3.1", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", "resolve": "^1.20.0", "resolve.exports": "^1.1.0", "slash": "^3.0.0" @@ -3330,45 +3318,45 @@ } }, "node_modules/jest-resolve-dependencies": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.4.5.tgz", - "integrity": "sha512-elEVvkvRK51y037NshtEkEnukMBWvlPzZHiL847OrIljJ8yIsujD2GXRPqDXC4rEVKbcdsy7W0FxoZb4WmEs7w==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.3.1.tgz", + "integrity": "sha512-X7iLzY8pCiYOnvYo2YrK3P9oSE8/3N2f4pUZMJ8IUcZnT81vlSonya1KTO9ZfKGuC+svE6FHK/XOb8SsoRUV1A==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-snapshot": "^27.4.5" + "@jest/types": "^27.2.5", + "jest-regex-util": "^27.0.6", + "jest-snapshot": "^27.3.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-runner": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.4.5.tgz", - "integrity": "sha512-/irauncTfmY1WkTaRQGRWcyQLzK1g98GYG/8QvIPviHgO1Fqz1JYeEIsSfF+9mc/UTA6S+IIHFgKyvUrtiBIZg==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.3.1.tgz", + "integrity": "sha512-r4W6kBn6sPr3TBwQNmqE94mPlYVn7fLBseeJfo4E2uCTmAyDFm2O5DYAQAFP7Q3YfiA/bMwg8TVsciP7k0xOww==", "dev": true, "dependencies": { - "@jest/console": "^27.4.2", - "@jest/environment": "^27.4.4", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", + "@jest/console": "^27.3.1", + "@jest/environment": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.8.1", "exit": "^0.1.2", "graceful-fs": "^4.2.4", - "jest-docblock": "^27.4.0", - "jest-environment-jsdom": "^27.4.4", - "jest-environment-node": "^27.4.4", - "jest-haste-map": "^27.4.5", - "jest-leak-detector": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-resolve": "^27.4.5", - "jest-runtime": "^27.4.5", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.5", + "jest-docblock": "^27.0.6", + "jest-environment-jsdom": "^27.3.1", + "jest-environment-node": "^27.3.1", + "jest-haste-map": "^27.3.1", + "jest-leak-detector": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-resolve": "^27.3.1", + "jest-runtime": "^27.3.1", + "jest-util": "^27.3.1", + "jest-worker": "^27.3.1", "source-map-support": "^0.5.6", "throat": "^6.0.1" }, @@ -3377,18 +3365,18 @@ } }, "node_modules/jest-runtime": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.4.5.tgz", - "integrity": "sha512-CIYqwuJQXHQtPd/idgrx4zgJ6iCb6uBjQq1RSAGQrw2S8XifDmoM1Ot8NRd80ooAm+ZNdHVwsktIMGlA1F1FAQ==", - "dev": true, - "dependencies": { - "@jest/console": "^27.4.2", - "@jest/environment": "^27.4.4", - "@jest/globals": "^27.4.4", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.3.1.tgz", + "integrity": "sha512-qtO6VxPbS8umqhEDpjA4pqTkKQ1Hy4ZSi9mDVeE9Za7LKBo2LdW2jmT+Iod3XFaJqINikZQsn2wEi0j9wPRbLg==", + "dev": true, + "dependencies": { + "@jest/console": "^27.3.1", + "@jest/environment": "^27.3.1", + "@jest/globals": "^27.3.1", + "@jest/source-map": "^27.0.6", + "@jest/test-result": "^27.3.1", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", "@types/yargs": "^16.0.0", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", @@ -3397,14 +3385,14 @@ "exit": "^0.1.2", "glob": "^7.1.3", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.5", - "jest-message-util": "^27.4.2", - "jest-mock": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.5", - "jest-snapshot": "^27.4.5", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", + "jest-haste-map": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-mock": "^27.3.0", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.3.1", + "jest-snapshot": "^27.3.1", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", "slash": "^3.0.0", "strip-bom": "^4.0.0", "yargs": "^16.2.0" @@ -3414,9 +3402,9 @@ } }, "node_modules/jest-serializer": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.4.0.tgz", - "integrity": "sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.0.6.tgz", + "integrity": "sha512-PtGdVK9EGC7dsaziskfqaAPib6wTViY3G8E5wz9tLVPhHyiDNTZn/xjZ4khAw+09QkoOVpn7vF5nPSN6dtBexA==", "dev": true, "dependencies": { "@types/node": "*", @@ -3427,9 +3415,9 @@ } }, "node_modules/jest-snapshot": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.4.5.tgz", - "integrity": "sha512-eCi/iM1YJFrJWiT9de4+RpWWWBqsHiYxFG9V9o/n0WXs6GpW4lUt4FAHAgFPTLPqCUVzrMQmSmTZSgQzwqR7IQ==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.3.1.tgz", + "integrity": "sha512-APZyBvSgQgOT0XumwfFu7X3G5elj6TGhCBLbBdn3R1IzYustPGPE38F51dBWMQ8hRXa9je0vAdeVDtqHLvB6lg==", "dev": true, "dependencies": { "@babel/core": "^7.7.2", @@ -3438,23 +3426,23 @@ "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", "@babel/types": "^7.0.0", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", "@types/babel__traverse": "^7.0.4", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^27.4.2", + "expect": "^27.3.1", "graceful-fs": "^4.2.4", - "jest-diff": "^27.4.2", - "jest-get-type": "^27.4.0", - "jest-haste-map": "^27.4.5", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-resolve": "^27.4.5", - "jest-util": "^27.4.2", + "jest-diff": "^27.3.1", + "jest-get-type": "^27.3.1", + "jest-haste-map": "^27.3.1", + "jest-matcher-utils": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-resolve": "^27.3.1", + "jest-util": "^27.3.1", "natural-compare": "^1.4.0", - "pretty-format": "^27.4.2", + "pretty-format": "^27.3.1", "semver": "^7.3.2" }, "engines": { @@ -3477,12 +3465,12 @@ } }, "node_modules/jest-util": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.4.2.tgz", - "integrity": "sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.3.1.tgz", + "integrity": "sha512-8fg+ifEH3GDryLQf/eKZck1DEs2YuVPBCMOaHQxVVLmQwl/CDhWzrvChTX4efLZxGrw+AA0mSXv78cyytBt/uw==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -3494,26 +3482,26 @@ } }, "node_modules/jest-validate": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.2.tgz", - "integrity": "sha512-hWYsSUej+Fs8ZhOm5vhWzwSLmVaPAxRy+Mr+z5MzeaHm9AxUpXdoVMEW4R86y5gOobVfBsMFLk4Rb+QkiEpx1A==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.3.1.tgz", + "integrity": "sha512-3H0XCHDFLA9uDII67Bwi1Vy7AqwA5HqEEjyy934lgVhtJ3eisw6ShOF1MDmRPspyikef5MyExvIm0/TuLzZ86Q==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", + "jest-get-type": "^27.3.1", "leven": "^3.1.0", - "pretty-format": "^27.4.2" + "pretty-format": "^27.3.1" }, "engines": { "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, "node_modules/jest-validate/node_modules/camelcase": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.1.tgz", - "integrity": "sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", "dev": true, "engines": { "node": ">=10" @@ -3523,17 +3511,17 @@ } }, "node_modules/jest-watcher": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.4.2.tgz", - "integrity": "sha512-NJvMVyyBeXfDezhWzUOCOYZrUmkSCiatpjpm+nFUid74OZEHk6aMLrZAukIiFDwdbqp6mTM6Ui1w4oc+8EobQg==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.3.1.tgz", + "integrity": "sha512-9/xbV6chABsGHWh9yPaAGYVVKurWoP3ZMCv6h+O1v9/+pkOroigs6WzZ0e9gLP/njokUwM7yQhr01LKJVMkaZA==", "dev": true, "dependencies": { - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/test-result": "^27.3.1", + "@jest/types": "^27.2.5", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "jest-util": "^27.4.2", + "jest-util": "^27.3.1", "string-length": "^4.0.1" }, "engines": { @@ -3541,9 +3529,9 @@ } }, "node_modules/jest-worker": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.5.tgz", - "integrity": "sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.3.1.tgz", + "integrity": "sha512-ks3WCzsiZaOPJl/oMsDjaf0TRiSv7ctNgs0FqRr2nARsovz6AWWy4oLElwcquGSz692DzgZQrCLScPNs5YlC4g==", "dev": true, "dependencies": { "@types/node": "*", @@ -3816,19 +3804,19 @@ } }, "node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", + "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "version": "2.1.31", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", + "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", "dependencies": { - "mime-db": "1.51.0" + "mime-db": "1.48.0" }, "engines": { "node": ">= 0.6" @@ -3862,14 +3850,14 @@ "dev": true }, "node_modules/mongodb": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz", - "integrity": "sha512-Psm+g3/wHXhjBEktkxXsFMZvd3nemI0r3IPsE0bU+4//PnvNWKkzhZcEsbPcYiWqe8XqXJJEg4Tgtr7Raw67Yw==", + "version": "3.6.9", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.9.tgz", + "integrity": "sha512-1nSCKgSunzn/CXwgOWgbPHUWOO5OfERcuOWISmqd610jn0s8BU9K4879iJVabqgpPPbA6hO7rG48eq+fGED3Mg==", "dependencies": { "bl": "^2.2.1", "bson": "^1.1.4", "denque": "^1.4.1", - "optional-require": "^1.1.8", + "optional-require": "^1.0.3", "safe-buffer": "^5.1.2" }, "engines": { @@ -3899,14 +3887,6 @@ } } }, - "node_modules/mongodb/node_modules/bson": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", - "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==", - "engines": { - "node": ">=0.6.19" - } - }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -3932,6 +3912,15 @@ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", "dev": true }, + "node_modules/node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/node-releases": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", @@ -3974,9 +3963,9 @@ } }, "node_modules/object-inspect": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz", - "integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4018,12 +4007,9 @@ } }, "node_modules/optional-require": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz", - "integrity": "sha512-jq83qaUb0wNg9Krv1c5OQ+58EK+vHde6aBPzLvPPqJm89UQWsvSuFy9X/OSNJnFeSOKo7btE0n8Nl2+nE+z5nA==", - "dependencies": { - "require-at": "^1.0.6" - }, + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", + "integrity": "sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA==", "engines": { "node": ">=4" } @@ -4152,10 +4138,13 @@ } }, "node_modules/pirates": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz", - "integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", "dev": true, + "dependencies": { + "node-modules-regexp": "^1.0.0" + }, "engines": { "node": ">= 6" } @@ -4182,12 +4171,12 @@ } }, "node_modules/pretty-format": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.2.tgz", - "integrity": "sha512-p0wNtJ9oLuvgOQDEIZ9zQjZffK7KtyR6Si0jnXULIDwrlNF8Cuir3AZP0hHv0jmKuNN/edOnbMjnzd4uTcmWiw==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.3.1.tgz", + "integrity": "sha512-DR/c+pvFc52nLimLROYjnXPtolawm+uWDxr4FjuLDLUn+ktWnSN851KoHwHzzqq6rfCOjkzN8FLgDrSub6UDuA==", "dev": true, "dependencies": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" @@ -4345,14 +4334,6 @@ "node": ">=4" } }, - "node_modules/require-at": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz", - "integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g==", - "engines": { - "node": ">=4" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -4546,9 +4527,9 @@ } }, "node_modules/signal-exit": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", - "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", + "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", "dev": true }, "node_modules/sisteransi": { @@ -4576,9 +4557,9 @@ } }, "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==", + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", + "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", "dev": true, "dependencies": { "buffer-from": "^1.0.0", @@ -4708,9 +4689,9 @@ } }, "node_modules/superagent/node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -4743,9 +4724,9 @@ "dev": true }, "node_modules/superagent/node_modules/qs": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.2.tgz", - "integrity": "sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw==", + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", + "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", "dev": true, "dependencies": { "side-channel": "^1.0.4" @@ -4947,9 +4928,9 @@ } }, "node_modules/ts-jest": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.1.tgz", - "integrity": "sha512-Ds0VkB+cB+8g2JUmP/GKWndeZcCKrbe6jzolGrVWdqVUFByY/2KDHqxJ7yBSon7hDB1TA4PXxjfZ+JjzJisvgA==", + "version": "27.0.7", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.7.tgz", + "integrity": "sha512-O41shibMqzdafpuP+CkrOL7ykbmLh+FqQrXEmV9CydQ5JBk0Sj0uAEF5TNNe94fZWKm3yYvWa/IbyV4Yg1zK2Q==", "dev": true, "dependencies": { "bs-logger": "0.x", @@ -4971,7 +4952,6 @@ "@babel/core": ">=7.0.0-beta.0 <8", "@types/jest": "^27.0.0", "babel-jest": ">=27.0.0 <28", - "esbuild": "~0.14.0", "jest": "^27.0.0", "typescript": ">=3.8 <5.0" }, @@ -4984,9 +4964,6 @@ }, "babel-jest": { "optional": true - }, - "esbuild": { - "optional": true } } }, @@ -5110,9 +5087,9 @@ } }, "node_modules/typescript": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz", - "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz", + "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -5311,9 +5288,9 @@ } }, "node_modules/ws": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", - "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", + "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", "dev": true, "engines": { "node": ">=8.3.0" @@ -5406,25 +5383,25 @@ } }, "@babel/compat-data": { - "version": "7.16.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.4.tgz", - "integrity": "sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.0.tgz", + "integrity": "sha512-DGjt2QZse5SGd9nfOSqO4WLJ8NN/oHkijbXbPrxuoJO3oIPJL3TciZs9FX+cOHNiY9E9l0opL8g7BmLe3T+9ew==", "dev": true }, "@babel/core": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.5.tgz", - "integrity": "sha512-wUcenlLzuWMZ9Zt8S0KmFwGlH6QKRh3vsm/dhDA3CHkiTA45YuG1XkHRcNRl73EFPXDp/d5kVOU0/y7x2w6OaQ==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.0.tgz", + "integrity": "sha512-mYZEvshBRHGsIAiyH5PzCFTCfbWfoYbO/jcSdXQSUQu1/pW0xDZAUP7KEc32heqWTAfAHhV9j1vH8Sav7l+JNQ==", "dev": true, "requires": { "@babel/code-frame": "^7.16.0", - "@babel/generator": "^7.16.5", - "@babel/helper-compilation-targets": "^7.16.3", - "@babel/helper-module-transforms": "^7.16.5", - "@babel/helpers": "^7.16.5", - "@babel/parser": "^7.16.5", + "@babel/generator": "^7.16.0", + "@babel/helper-compilation-targets": "^7.16.0", + "@babel/helper-module-transforms": "^7.16.0", + "@babel/helpers": "^7.16.0", + "@babel/parser": "^7.16.0", "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.5", + "@babel/traverse": "^7.16.0", "@babel/types": "^7.16.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", @@ -5435,9 +5412,9 @@ }, "dependencies": { "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -5458,9 +5435,9 @@ } }, "@babel/generator": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.5.tgz", - "integrity": "sha512-kIvCdjZqcdKqoDbVVdt5R99icaRtrtYhYK/xux5qiWCBmfdvEYMFZ68QCrpE5cbFM1JsuArUNs1ZkuKtTtUcZA==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.0.tgz", + "integrity": "sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew==", "dev": true, "requires": { "@babel/types": "^7.16.0", @@ -5488,15 +5465,6 @@ "semver": "^6.3.0" } }, - "@babel/helper-environment-visitor": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.5.tgz", - "integrity": "sha512-ODQyc5AnxmZWm/R2W7fzhamOk1ey8gSguo5SGvF0zcB3uUzRpTRmM/jmLSm9bDMyPlvbyJ+PwPEK0BWIoZ9wjg==", - "dev": true, - "requires": { - "@babel/types": "^7.16.0" - } - }, "@babel/helper-function-name": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz", @@ -5526,6 +5494,15 @@ "@babel/types": "^7.16.0" } }, + "@babel/helper-member-expression-to-functions": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz", + "integrity": "sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ==", + "dev": true, + "requires": { + "@babel/types": "^7.16.0" + } + }, "@babel/helper-module-imports": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz", @@ -5536,27 +5513,48 @@ } }, "@babel/helper-module-transforms": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.5.tgz", - "integrity": "sha512-CkvMxgV4ZyyioElFwcuWnDCcNIeyqTkCm9BxXZi73RR1ozqlpboqsbGUNvRTflgZtFbbJ1v5Emvm+lkjMYY/LQ==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz", + "integrity": "sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA==", "dev": true, "requires": { - "@babel/helper-environment-visitor": "^7.16.5", "@babel/helper-module-imports": "^7.16.0", + "@babel/helper-replace-supers": "^7.16.0", "@babel/helper-simple-access": "^7.16.0", "@babel/helper-split-export-declaration": "^7.16.0", "@babel/helper-validator-identifier": "^7.15.7", "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.5", + "@babel/traverse": "^7.16.0", + "@babel/types": "^7.16.0" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz", + "integrity": "sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw==", + "dev": true, + "requires": { "@babel/types": "^7.16.0" } }, "@babel/helper-plugin-utils": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.5.tgz", - "integrity": "sha512-59KHWHXxVA9K4HNF4sbHCf+eJeFe0Te/ZFGqBT4OjXhrwvA04sGfaEGsVTdsjoszq0YTP49RC9UKe5g8uN2RwQ==", + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", "dev": true }, + "@babel/helper-replace-supers": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz", + "integrity": "sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.16.0", + "@babel/helper-optimise-call-expression": "^7.16.0", + "@babel/traverse": "^7.16.0", + "@babel/types": "^7.16.0" + } + }, "@babel/helper-simple-access": { "version": "7.16.0", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz", @@ -5588,13 +5586,13 @@ "dev": true }, "@babel/helpers": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.5.tgz", - "integrity": "sha512-TLgi6Lh71vvMZGEkFuIxzaPsyeYCHQ5jJOOX1f0xXn0uciFuE8cEk0wyBquMcCxBXZ5BJhE2aUB7pnWTD150Tw==", + "version": "7.16.3", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.3.tgz", + "integrity": "sha512-Xn8IhDlBPhvYTvgewPKawhADichOsbkZuzN7qz2BusOM0brChsyXMDJvldWaYMMUNiCQdQzNEioXTp3sC8Nt8w==", "dev": true, "requires": { "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.5", + "@babel/traverse": "^7.16.3", "@babel/types": "^7.16.0" } }, @@ -5668,9 +5666,9 @@ } }, "@babel/parser": { - "version": "7.16.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.6.tgz", - "integrity": "sha512-Gr86ujcNuPDnNOY8mi383Hvi8IYrJVJYuf3XcuBM/Dgd+bINn/7tHqsj+tKkoreMbmGsFLsltI/JJd8fOFWGDQ==", + "version": "7.16.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.3.tgz", + "integrity": "sha512-dcNwU1O4sx57ClvLBVFbEgx0UZWfd0JQX5X6fxFRCLHelFBGXFfSz6Y0FAq2PEwUqlqLkdVjVr4VASEOuUnLJw==", "dev": true }, "@babel/plugin-syntax-async-generators": { @@ -5782,12 +5780,12 @@ } }, "@babel/plugin-syntax-typescript": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.5.tgz", - "integrity": "sha512-/d4//lZ1Vqb4mZ5xTep3dDK888j7BGM/iKqBmndBaoYAFPlPKrGU608VVBz5JeyAb6YQDjRu1UKqj86UhwWVgw==", + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.0.tgz", + "integrity": "sha512-Xv6mEXqVdaqCBfJFyeab0fH2DnUoMsDmhamxsSi4j8nLd4Vtw213WMJr55xxqipC/YVWyPY3K0blJncPYji+dQ==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.16.5" + "@babel/helper-plugin-utils": "^7.14.5" } }, "@babel/template": { @@ -5802,27 +5800,26 @@ } }, "@babel/traverse": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.5.tgz", - "integrity": "sha512-FOCODAzqUMROikDYLYxl4nmwiLlu85rNqBML/A5hKRVXG2LV8d0iMqgPzdYTcIpjZEBB7D6UDU9vxRZiriASdQ==", + "version": "7.16.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.3.tgz", + "integrity": "sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag==", "dev": true, "requires": { "@babel/code-frame": "^7.16.0", - "@babel/generator": "^7.16.5", - "@babel/helper-environment-visitor": "^7.16.5", + "@babel/generator": "^7.16.0", "@babel/helper-function-name": "^7.16.0", "@babel/helper-hoist-variables": "^7.16.0", "@babel/helper-split-export-declaration": "^7.16.0", - "@babel/parser": "^7.16.5", + "@babel/parser": "^7.16.3", "@babel/types": "^7.16.0", "debug": "^4.1.0", "globals": "^11.1.0" }, "dependencies": { "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -5887,103 +5884,134 @@ "dev": true }, "@jest/console": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.4.2.tgz", - "integrity": "sha512-xknHThRsPB/To1FUbi6pCe43y58qFC03zfb6R7fDb/FfC7k2R3i1l+izRBJf8DI46KhYGRaF14Eo9A3qbBoixg==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.3.1.tgz", + "integrity": "sha512-RkFNWmv0iui+qsOr/29q9dyfKTTT5DCuP31kUwg7rmOKPT/ozLeGLKJKVIiOfbiKyleUZKIrHwhmiZWVe8IMdw==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^27.4.2", - "jest-util": "^27.4.2", + "jest-message-util": "^27.3.1", + "jest-util": "^27.3.1", "slash": "^3.0.0" } }, "@jest/core": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.4.5.tgz", - "integrity": "sha512-3tm/Pevmi8bDsgvo73nX8p/WPng6KWlCyScW10FPEoN1HU4pwI83tJ3TsFvi1FfzsjwUlMNEPowgb/rPau/LTQ==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.3.1.tgz", + "integrity": "sha512-DMNE90RR5QKx0EA+wqe3/TNEwiRpOkhshKNxtLxd4rt3IZpCt+RSL+FoJsGeblRZmqdK4upHA/mKKGPPRAifhg==", "dev": true, "requires": { - "@jest/console": "^27.4.2", - "@jest/reporters": "^27.4.5", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", + "@jest/console": "^27.3.1", + "@jest/reporters": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", "emittery": "^0.8.1", "exit": "^0.1.2", "graceful-fs": "^4.2.4", - "jest-changed-files": "^27.4.2", - "jest-config": "^27.4.5", - "jest-haste-map": "^27.4.5", - "jest-message-util": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.5", - "jest-resolve-dependencies": "^27.4.5", - "jest-runner": "^27.4.5", - "jest-runtime": "^27.4.5", - "jest-snapshot": "^27.4.5", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", - "jest-watcher": "^27.4.2", + "jest-changed-files": "^27.3.0", + "jest-config": "^27.3.1", + "jest-haste-map": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.3.1", + "jest-resolve-dependencies": "^27.3.1", + "jest-runner": "^27.3.1", + "jest-runtime": "^27.3.1", + "jest-snapshot": "^27.3.1", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", + "jest-watcher": "^27.3.1", "micromatch": "^4.0.4", "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" + }, + "dependencies": { + "jest-config": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.3.1.tgz", + "integrity": "sha512-KY8xOIbIACZ/vdYCKSopL44I0xboxC751IX+DXL2+Wx6DKNycyEfV3rryC3BPm5Uq/BBqDoMrKuqLEUNJmMKKg==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^27.3.1", + "@jest/types": "^27.2.5", + "babel-jest": "^27.3.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.4", + "jest-circus": "^27.3.1", + "jest-environment-jsdom": "^27.3.1", + "jest-environment-node": "^27.3.1", + "jest-get-type": "^27.3.1", + "jest-jasmine2": "^27.3.1", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.3.1", + "jest-runner": "^27.3.1", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", + "micromatch": "^4.0.4", + "pretty-format": "^27.3.1" + } + } } }, "@jest/environment": { - "version": "27.4.4", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.4.4.tgz", - "integrity": "sha512-q+niMx7cJgt/t/b6dzLOh4W8Ef/8VyKG7hxASK39jakijJzbFBGpptx3RXz13FFV7OishQ9lTbv+dQ5K3EhfDQ==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.3.1.tgz", + "integrity": "sha512-BCKCj4mOVLme6Tanoyc9k0ultp3pnmuyHw73UHRPeeZxirsU/7E3HC4le/VDb/SMzE1JcPnto+XBKFOcoiJzVw==", "dev": true, "requires": { - "@jest/fake-timers": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/fake-timers": "^27.3.1", + "@jest/types": "^27.2.5", "@types/node": "*", - "jest-mock": "^27.4.2" + "jest-mock": "^27.3.0" } }, "@jest/fake-timers": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.4.2.tgz", - "integrity": "sha512-f/Xpzn5YQk5adtqBgvw1V6bF8Nx3hY0OIRRpCvWcfPl0EAjdqWPdhH3t/3XpiWZqtjIEHDyMKP9ajpva1l4Zmg==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.3.1.tgz", + "integrity": "sha512-M3ZFgwwlqJtWZ+QkBG5NmC23A9w+A6ZxNsO5nJxJsKYt4yguBd3i8TpjQz5NfCX91nEve1KqD9RA2Q+Q1uWqoA==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "@sinonjs/fake-timers": "^8.0.1", "@types/node": "*", - "jest-message-util": "^27.4.2", - "jest-mock": "^27.4.2", - "jest-util": "^27.4.2" + "jest-message-util": "^27.3.1", + "jest-mock": "^27.3.0", + "jest-util": "^27.3.1" } }, "@jest/globals": { - "version": "27.4.4", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.4.4.tgz", - "integrity": "sha512-bqpqQhW30BOreXM8bA8t8JbOQzsq/WnPTnBl+It3UxAD9J8yxEAaBEylHx1dtBapAr/UBk8GidXbzmqnee8tYQ==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.3.1.tgz", + "integrity": "sha512-Q651FWiWQAIFiN+zS51xqhdZ8g9b88nGCobC87argAxA7nMfNQq0Q0i9zTfQYgLa6qFXk2cGANEqfK051CZ8Pg==", "dev": true, "requires": { - "@jest/environment": "^27.4.4", - "@jest/types": "^27.4.2", - "expect": "^27.4.2" + "@jest/environment": "^27.3.1", + "@jest/types": "^27.2.5", + "expect": "^27.3.1" } }, "@jest/reporters": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.4.5.tgz", - "integrity": "sha512-3orsG4vi8zXuBqEoy2LbnC1kuvkg1KQUgqNxmxpQgIOQEPeV0onvZu+qDQnEoX8qTQErtqn/xzcnbpeTuOLSiA==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.3.1.tgz", + "integrity": "sha512-m2YxPmL9Qn1emFVgZGEiMwDntDxRRQ2D58tiDQlwYTg5GvbFOKseYCcHtn0WsI8CG4vzPglo3nqbOiT8ySBT/w==", "dev": true, "requires": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.4.2", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", + "@jest/console": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", @@ -5995,10 +6023,10 @@ "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.0.2", - "jest-haste-map": "^27.4.5", - "jest-resolve": "^27.4.5", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.5", + "jest-haste-map": "^27.3.1", + "jest-resolve": "^27.3.1", + "jest-util": "^27.3.1", + "jest-worker": "^27.3.1", "slash": "^3.0.0", "source-map": "^0.6.0", "string-length": "^4.0.1", @@ -6007,9 +6035,9 @@ } }, "@jest/source-map": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.4.0.tgz", - "integrity": "sha512-Ntjx9jzP26Bvhbm93z/AKcPRj/9wrkI88/gK60glXDx1q+IeI0rf7Lw2c89Ch6ofonB0On/iRDreQuQ6te9pgQ==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.0.6.tgz", + "integrity": "sha512-Fek4mi5KQrqmlY07T23JRi0e7Z9bXTOOD86V/uS0EIW4PClvPDqZOyFlLpNJheS6QI0FNX1CgmPjtJ4EA/2M+g==", "dev": true, "requires": { "callsites": "^3.0.0", @@ -6018,45 +6046,45 @@ } }, "@jest/test-result": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.4.2.tgz", - "integrity": "sha512-kr+bCrra9jfTgxHXHa2UwoQjxvQk3Am6QbpAiJ5x/50LW8llOYrxILkqY0lZRW/hu8FXesnudbql263+EW9iNA==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.3.1.tgz", + "integrity": "sha512-mLn6Thm+w2yl0opM8J/QnPTqrfS4FoXsXF2WIWJb2O/GBSyResL71BRuMYbYRsGt7ELwS5JGcEcGb52BNrumgg==", "dev": true, "requires": { - "@jest/console": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/console": "^27.3.1", + "@jest/types": "^27.2.5", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" } }, "@jest/test-sequencer": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.4.5.tgz", - "integrity": "sha512-n5woIn/1v+FT+9hniymHPARA9upYUmfi5Pw9ewVwXCDlK4F5/Gkees9v8vdjGdAIJ2MPHLHodiajLpZZanWzEQ==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.3.1.tgz", + "integrity": "sha512-siySLo07IMEdSjA4fqEnxfIX8lB/lWYsBPwNFtkOvsFQvmBrL3yj3k3uFNZv/JDyApTakRpxbKLJ3CT8UGVCrA==", "dev": true, "requires": { - "@jest/test-result": "^27.4.2", + "@jest/test-result": "^27.3.1", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.5", - "jest-runtime": "^27.4.5" + "jest-haste-map": "^27.3.1", + "jest-runtime": "^27.3.1" } }, "@jest/transform": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.4.5.tgz", - "integrity": "sha512-PuMet2UlZtlGzwc6L+aZmR3I7CEBpqadO03pU40l2RNY2fFJ191b9/ITB44LNOhVtsyykx0OZvj0PCyuLm7Eew==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.3.1.tgz", + "integrity": "sha512-3fSvQ02kuvjOI1C1ssqMVBKJpZf6nwoCiSu00zAKh5nrp3SptNtZy/8s5deayHnqxhjD9CWDJ+yqQwuQ0ZafXQ==", "dev": true, "requires": { "@babel/core": "^7.1.0", - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "babel-plugin-istanbul": "^6.0.0", "chalk": "^4.0.0", "convert-source-map": "^1.4.0", "fast-json-stable-stringify": "^2.0.0", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.5", - "jest-regex-util": "^27.4.0", - "jest-util": "^27.4.2", + "jest-haste-map": "^27.3.1", + "jest-regex-util": "^27.0.6", + "jest-util": "^27.3.1", "micromatch": "^4.0.4", "pirates": "^4.0.1", "slash": "^3.0.0", @@ -6065,9 +6093,9 @@ } }, "@jest/types": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz", - "integrity": "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg==", + "version": "27.2.5", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.2.5.tgz", + "integrity": "sha512-nmuM4VuDtCZcY+eTpw+0nvstwReMsjPoj7ZR80/BbixulhLaiX+fbv8oeLW8WZlJMcsGQsTmMKT/iTZu1Uy/lQ==", "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", @@ -6126,9 +6154,9 @@ "dev": true }, "@types/babel__core": { - "version": "7.1.17", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.17.tgz", - "integrity": "sha512-6zzkezS9QEIL8yCBvXWxPTJPNuMeECJVxSOhxNY/jfq9LxOTHivaYTqr37n9LknWWRTIkzqH2UilS5QFvfa90A==", + "version": "7.1.16", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.16.tgz", + "integrity": "sha512-EAEHtisTMM+KaKwfWdC3oyllIqswlznXCIVCt7/oRNrh+DhgT4UEBNC/jlADNjvw7UnfbcdkGQcPVZ1xYiLcrQ==", "dev": true, "requires": { "@babel/parser": "^7.1.0", @@ -6167,9 +6195,9 @@ } }, "@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", "dev": true, "requires": { "@types/connect": "*", @@ -6177,18 +6205,18 @@ } }, "@types/bson": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.2.0.tgz", - "integrity": "sha512-ELCPqAdroMdcuxqwMgUpifQyRoTpyYCNr1V9xKyF40VsBobsj+BbWNRvwGchMgBPGqkw655ypkjj2MEF5ywVwg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.3.tgz", + "integrity": "sha512-mVRvYnTOZJz3ccpxhr3wgxVmSeiYinW+zlzQz3SXWaJmD1DuL05Jeq7nKw3SnbKmbleW5qrLG5vdyWe/A9sXhw==", "dev": true, "requires": { - "bson": "*" + "@types/node": "*" } }, "@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "version": "3.4.34", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.34.tgz", + "integrity": "sha512-ePPA/JuI+X0vb+gSWlPKOY0NdNAie/rPUqX2GUPpbZwiKTkSPhjXWuee47E4MtE54QVzGCQMQkAL6JhV2E1+cQ==", "dev": true, "requires": { "@types/node": "*" @@ -6216,9 +6244,9 @@ "dev": true }, "@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "version": "4.17.12", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.12.tgz", + "integrity": "sha512-pTYas6FrP15B1Oa0bkN5tQMNqOcVXa9j4FTFtO8DWI9kppKib+6NJtfTOOLcwxuuYvcX2+dVG6et1SxW/Kc17Q==", "dev": true, "requires": { "@types/body-parser": "*", @@ -6228,9 +6256,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.17.26", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.26.tgz", - "integrity": "sha512-zeu3tpouA043RHxW0gzRxwCHchMgftE8GArRsvYT0ByDMbn19olQHx5jLue0LxWY6iYtXb7rXmuVtSkhy9YZvQ==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.21.tgz", + "integrity": "sha512-gwCiEZqW6f7EoR8TTEfalyEhb1zA5jQJnRngr97+3pzMaO1RKoI1w2bw07TK72renMUVWcWS5mLI6rk1NqN0nA==", "dev": true, "requires": { "@types/node": "*", @@ -6272,9 +6300,9 @@ } }, "@types/jest": { - "version": "27.0.3", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.3.tgz", - "integrity": "sha512-cmmwv9t7gBYt7hNKH5Spu7Kuu/DotGa+Ff+JGRKZ4db5eh8PnKS4LuebJ3YLUoyOyIHraTGyULn23YtEAm0VSg==", + "version": "27.0.2", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-27.0.2.tgz", + "integrity": "sha512-4dRxkS/AFX0c5XW6IPMNOydLn2tEhNhJV7DnYK+0bjoJZ+QTmfucBlihX7aoEsh/ocYtkLC73UbnBXBXIxsULA==", "dev": true, "requires": { "jest-diff": "^27.0.0", @@ -6288,9 +6316,9 @@ "dev": true }, "@types/mongodb": { - "version": "3.6.20", - "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.20.tgz", - "integrity": "sha512-WcdpPJCakFzcWWD9juKoZbRtQxKIMYF/JIAM4JrNHrMcnJL6/a2NWjXxW7fo9hxboxxkg+icff8d7+WIEvKgYQ==", + "version": "3.6.17", + "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.6.17.tgz", + "integrity": "sha512-9hhgvYPdC5iHyyksPcKCu45gfaAIPQHKHGdvNXu4582DmOZX3wrUJIJPT40o4G1oTKPgpMMFqZglOTjhnYoF+A==", "dev": true, "requires": { "@types/bson": "*", @@ -6298,42 +6326,42 @@ } }, "@types/node": { - "version": "15.14.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.14.9.tgz", - "integrity": "sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A==", + "version": "15.12.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz", + "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==", "dev": true }, "@types/prettier": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.2.tgz", - "integrity": "sha512-ekoj4qOQYp7CvjX8ZDBgN86w3MqQhLE1hczEJbEIjgFEumDy+na/4AJAbLXfgEWFNB2pKadM5rPFtuSGMWK7xA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.1.tgz", + "integrity": "sha512-Fo79ojj3vdEZOHg3wR9ksAMRz4P3S5fDB5e/YWZiFnyFQI1WY2Vftu9XoXVVtJfxB7Bpce/QTqWSSntkz2Znrw==", "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==", + "version": "6.9.6", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.6.tgz", + "integrity": "sha512-0/HnwIfW4ki2D8L8c9GVcG5I72s9jP5GSLVF0VIXDW00kmIpA6O33G7a8n59Tmh7Nz0WUC3rSb7PTY/sdW2JzA==", "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==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==", "dev": true }, "@types/redis": { - "version": "2.8.32", - "resolved": "https://registry.npmjs.org/@types/redis/-/redis-2.8.32.tgz", - "integrity": "sha512-7jkMKxcGq9p242exlbsVzuJb57KqHRhNl4dHoQu2Y5v9bCAbtIXXH0R3HleSQW4CTOqpHIYUW3t6tpUj4BVQ+w==", + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/@types/redis/-/redis-2.8.29.tgz", + "integrity": "sha512-/pjQ9lwnL/t1bEfRHQFEJB3kHCR65tpB19NEWmbqcgGgqrfeGo/9b4tUtHbClxQoy3+g6Esx2QRtV7fk7kBPYg==", "dev": true, "requires": { "@types/node": "*" } }, "@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "version": "1.13.9", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.9.tgz", + "integrity": "sha512-ZFqF6qa48XsPdjXV5Gsz0Zqmux2PerNd3a/ktL45mHpa19cuMi/cL8tcxdAx497yRh+QtYPuofjT9oWw9P7nkA==", "dev": true, "requires": { "@types/mime": "^1", @@ -6396,9 +6424,9 @@ } }, "acorn": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.6.0.tgz", - "integrity": "sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz", + "integrity": "sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q==", "dev": true }, "acorn-globals": { @@ -6435,9 +6463,9 @@ }, "dependencies": { "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -6512,16 +6540,16 @@ "dev": true }, "babel-jest": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.4.5.tgz", - "integrity": "sha512-3uuUTjXbgtODmSv/DXO9nZfD52IyC2OYTFaXGRzL0kpykzroaquCrD5+lZNafTvZlnNqZHt5pb0M08qVBZnsnA==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.3.1.tgz", + "integrity": "sha512-SjIF8hh/ir0peae2D6S6ZKRhUy7q/DnpH7k/V6fT4Bgs/LXXUztOpX4G2tCgq8mLo5HA9mN6NmlFMeYtKmIsTQ==", "dev": true, "requires": { - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.0.0", - "babel-preset-jest": "^27.4.0", + "babel-preset-jest": "^27.2.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", "slash": "^3.0.0" @@ -6556,9 +6584,9 @@ } }, "babel-plugin-jest-hoist": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz", - "integrity": "sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.2.0.tgz", + "integrity": "sha512-TOux9khNKdi64mW+0OIhcmbAn75tTlzKhxmiNXevQaPbrBYK7YKjP1jl6NHTJ6XR5UgUrJbCnWlKVnJn29dfjw==", "dev": true, "requires": { "@babel/template": "^7.3.3", @@ -6588,12 +6616,12 @@ } }, "babel-preset-jest": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.4.0.tgz", - "integrity": "sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg==", + "version": "27.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.2.0.tgz", + "integrity": "sha512-z7MgQ3peBwN5L5aCqBKnF6iqdlvZvFUQynEhu0J+X9nHLU72jO3iY331lcYrg+AssJ8q7xsv5/3AICzVmJ/wvg==", "dev": true, "requires": { - "babel-plugin-jest-hoist": "^27.4.0", + "babel-plugin-jest-hoist": "^27.2.0", "babel-preset-current-node-syntax": "^1.0.0" } }, @@ -6603,12 +6631,6 @@ "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 - }, "bl": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", @@ -6661,13 +6683,13 @@ "dev": true }, "browserslist": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz", - "integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==", + "version": "4.17.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.17.6.tgz", + "integrity": "sha512-uPgz3vyRTlEiCv4ee9KlsKgo2V6qPk7Jsn0KAn2OBqbqKo3iNcPEC1Ti6J4dwnz+aIRfEEEuOzC9IBk8tXUomw==", "dev": true, "requires": { - "caniuse-lite": "^1.0.30001286", - "electron-to-chromium": "^1.4.17", + "caniuse-lite": "^1.0.30001274", + "electron-to-chromium": "^1.3.886", "escalade": "^3.1.1", "node-releases": "^2.0.1", "picocolors": "^1.0.0" @@ -6692,23 +6714,9 @@ } }, "bson": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-4.6.0.tgz", - "integrity": "sha512-8jw1NU1hglS+Da1jDOUYuNcBJ4cNHCFIqzlwoFNnsTOg2R/ox0aTYcTiBN4dzRa9q7Cvy6XErh3L8ReTEb9AQQ==", - "dev": true, - "requires": { - "buffer": "^5.6.0" - } - }, - "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" - } + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", + "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==" }, "buffer-from": { "version": "1.1.2", @@ -6744,9 +6752,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001287", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001287.tgz", - "integrity": "sha512-4udbs9bc0hfNrcje++AxBuc6PfLNHwh3PO9kbwnfCQWyqtlzg3py0YgFu8jyRTTo85VAz4U+VLxSlID09vNtWA==", + "version": "1.0.30001279", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001279.tgz", + "integrity": "sha512-VfEHpzHEXj6/CxggTwSFoZBBYGQfQv9Cf42KPlO79sWXCD1QNKWKsKzFeWL7QpZHJQYAvocqV6Rty1yJMkqWLQ==", "dev": true }, "chalk": { @@ -6766,9 +6774,9 @@ "dev": true }, "ci-info": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz", - "integrity": "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.2.0.tgz", + "integrity": "sha512-dVqRX7fLUm8J6FgHJ418XuIgDLZDkYcDFTeL6TA2gt5WlIZUQrrH6EZrNClwT/H0FateUsZkGIOPRrLbP+PR9A==", "dev": true }, "cjs-module-lexer": { @@ -6859,16 +6867,16 @@ } }, "cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" }, "cookie-parser": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", - "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz", + "integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==", "requires": { - "cookie": "0.4.1", + "cookie": "0.4.0", "cookie-signature": "1.0.6" } }, @@ -6884,9 +6892,9 @@ "dev": true }, "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==" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, "cors": { "version": "2.8.5", @@ -6987,9 +6995,9 @@ "dev": true }, "denque": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", - "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz", + "integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ==" }, "depd": { "version": "1.1.2", @@ -7014,9 +7022,9 @@ "dev": true }, "diff-sequences": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.4.0.tgz", - "integrity": "sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.0.6.tgz", + "integrity": "sha512-ag6wfpBFyNXZ0p8pcuIDS//D8H062ZQJ3fzYxjpmeKjnz8W4pekL3AI8VohmyZmsWW2PWaHgjsmqR6L13101VQ==", "dev": true }, "domexception": { @@ -7047,9 +7055,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { - "version": "1.4.20", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.20.tgz", - "integrity": "sha512-N7ZVNrdzX8NE90OXEFBMsBf3fp8P/vVDUER3WCUZjzC7OkNTXHVoF6W9qVhq8+dA8tGnbDajzUpj2ISNVVyj+Q==", + "version": "1.3.894", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.894.tgz", + "integrity": "sha512-WY8pA4irAZ4cm/Pr7YFPtPLVqj3nU6d0SbfoHF6M7HZNONfPdAnYAarumqQ75go2LuN72uO9wGuCEqnfya/ytg==", "dev": true }, "emittery": { @@ -7146,17 +7154,17 @@ "dev": true }, "expect": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.4.2.tgz", - "integrity": "sha512-BjAXIDC6ZOW+WBFNg96J22D27Nq5ohn+oGcuP2rtOtcjuxNoV9McpQ60PcQWhdFOSBIQdR72e+4HdnbZTFSTyg==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/expect/-/expect-27.3.1.tgz", + "integrity": "sha512-MrNXV2sL9iDRebWPGOGFdPQRl2eDQNu/uhxIMShjjx74T6kC6jFIkmQ6OqXDtevjGUkyB2IT56RzDBqXf/QPCg==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "ansi-styles": "^5.0.0", - "jest-get-type": "^27.4.0", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-regex-util": "^27.4.0" + "jest-get-type": "^27.3.1", + "jest-matcher-utils": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-regex-util": "^27.0.6" }, "dependencies": { "ansi-styles": { @@ -7202,13 +7210,6 @@ "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" - }, - "dependencies": { - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" - } } }, "fast-json-stable-stringify": { @@ -7438,9 +7439,9 @@ }, "dependencies": { "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -7465,9 +7466,9 @@ }, "dependencies": { "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -7495,12 +7496,6 @@ "safer-buffer": ">= 2.1.2 < 3" } }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true - }, "import-local": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", @@ -7634,9 +7629,9 @@ }, "dependencies": { "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -7651,9 +7646,9 @@ } }, "istanbul-reports": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.1.tgz", - "integrity": "sha512-q1kvhAXWSsXfMjCdNHNPKZZv94OlspKnoGv+R9RGbnqOOQ0VbNfLFgQDVgi7hHenKsndGq3/o0OBdzDXthWcNw==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.5.tgz", + "integrity": "sha512-5+19PlhnGabNWB7kOFnuxT8H3T/iIyQzIbQMxXsURmmvKg86P2sbkrGOT77VnHw0Qr0gc2XzRaRfMZYYbSQCJQ==", "dev": true, "requires": { "html-escaper": "^2.0.0", @@ -7661,266 +7656,267 @@ } }, "jest": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.4.5.tgz", - "integrity": "sha512-uT5MiVN3Jppt314kidCk47MYIRilJjA/l2mxwiuzzxGUeJIvA8/pDaJOAX5KWvjAo7SCydcW0/4WEtgbLMiJkg==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest/-/jest-27.3.1.tgz", + "integrity": "sha512-U2AX0AgQGd5EzMsiZpYt8HyZ+nSVIh5ujQ9CPp9EQZJMjXIiSZpJNweZl0swatKRoqHWgGKM3zaSwm4Zaz87ng==", "dev": true, "requires": { - "@jest/core": "^27.4.5", + "@jest/core": "^27.3.1", "import-local": "^3.0.2", - "jest-cli": "^27.4.5" + "jest-cli": "^27.3.1" } }, "jest-changed-files": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.4.2.tgz", - "integrity": "sha512-/9x8MjekuzUQoPjDHbBiXbNEBauhrPU2ct7m8TfCg69ywt1y/N+yYwGh3gCpnqUS3klYWDU/lSNgv+JhoD2k1A==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.3.0.tgz", + "integrity": "sha512-9DJs9garMHv4RhylUMZgbdCJ3+jHSkpL9aaVKp13xtXAD80qLTLrqcDZL1PHA9dYA0bCI86Nv2BhkLpLhrBcPg==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "execa": "^5.0.0", "throat": "^6.0.1" } }, "jest-circus": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.4.5.tgz", - "integrity": "sha512-eTNWa9wsvBwPykhMMShheafbwyakcdHZaEYh5iRrQ0PFJxkDP/e3U/FvzGuKWu2WpwUA3C3hPlfpuzvOdTVqnw==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.3.1.tgz", + "integrity": "sha512-v1dsM9II6gvXokgqq6Yh2jHCpfg7ZqV4jWY66u7npz24JnhP3NHxI0sKT7+ZMQ7IrOWHYAaeEllOySbDbWsiXw==", "dev": true, "requires": { - "@jest/environment": "^27.4.4", - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/environment": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/types": "^27.2.5", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", - "expect": "^27.4.2", + "expect": "^27.3.1", "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.2", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-runtime": "^27.4.5", - "jest-snapshot": "^27.4.5", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.2", + "jest-each": "^27.3.1", + "jest-matcher-utils": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-runtime": "^27.3.1", + "jest-snapshot": "^27.3.1", + "jest-util": "^27.3.1", + "pretty-format": "^27.3.1", "slash": "^3.0.0", "stack-utils": "^2.0.3", "throat": "^6.0.1" } }, "jest-cli": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.4.5.tgz", - "integrity": "sha512-hrky3DSgE0u7sQxaCL7bdebEPHx5QzYmrGuUjaPLmPE8jx5adtvGuOlRspvMoVLTTDOHRnZDoRLYJuA+VCI7Hg==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.3.1.tgz", + "integrity": "sha512-WHnCqpfK+6EvT62me6WVs8NhtbjAS4/6vZJnk7/2+oOr50cwAzG4Wxt6RXX0hu6m1169ZGMlhYYUNeKBXCph/Q==", "dev": true, "requires": { - "@jest/core": "^27.4.5", - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/core": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/types": "^27.2.5", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.4", "import-local": "^3.0.2", - "jest-config": "^27.4.5", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", + "jest-config": "^27.3.1", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", "prompts": "^2.0.1", "yargs": "^16.2.0" - } - }, - "jest-config": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.4.5.tgz", - "integrity": "sha512-t+STVJtPt+fpqQ8GBw850NtSQbnDOw/UzdPfzDaHQ48/AylQlW7LHj3dH+ndxhC1UxJ0Q3qkq7IH+nM1skwTwA==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^27.4.5", - "@jest/types": "^27.4.2", - "babel-jest": "^27.4.5", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "deepmerge": "^4.2.2", - "glob": "^7.1.1", - "graceful-fs": "^4.2.4", - "jest-circus": "^27.4.5", - "jest-environment-jsdom": "^27.4.4", - "jest-environment-node": "^27.4.4", - "jest-get-type": "^27.4.0", - "jest-jasmine2": "^27.4.5", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.5", - "jest-runner": "^27.4.5", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", - "micromatch": "^4.0.4", - "pretty-format": "^27.4.2", - "slash": "^3.0.0" + }, + "dependencies": { + "jest-config": { + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.3.1.tgz", + "integrity": "sha512-KY8xOIbIACZ/vdYCKSopL44I0xboxC751IX+DXL2+Wx6DKNycyEfV3rryC3BPm5Uq/BBqDoMrKuqLEUNJmMKKg==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^27.3.1", + "@jest/types": "^27.2.5", + "babel-jest": "^27.3.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.4", + "jest-circus": "^27.3.1", + "jest-environment-jsdom": "^27.3.1", + "jest-environment-node": "^27.3.1", + "jest-get-type": "^27.3.1", + "jest-jasmine2": "^27.3.1", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.3.1", + "jest-runner": "^27.3.1", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", + "micromatch": "^4.0.4", + "pretty-format": "^27.3.1" + } + } } }, "jest-diff": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.4.2.tgz", - "integrity": "sha512-ujc9ToyUZDh9KcqvQDkk/gkbf6zSaeEg9AiBxtttXW59H/AcqEYp1ciXAtJp+jXWva5nAf/ePtSsgWwE5mqp4Q==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.3.1.tgz", + "integrity": "sha512-PCeuAH4AWUo2O5+ksW4pL9v5xJAcIKPUPfIhZBcG1RKv/0+dvaWTQK1Nrau8d67dp65fOqbeMdoil+6PedyEPQ==", "dev": true, "requires": { "chalk": "^4.0.0", - "diff-sequences": "^27.4.0", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.2" + "diff-sequences": "^27.0.6", + "jest-get-type": "^27.3.1", + "pretty-format": "^27.3.1" } }, "jest-docblock": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.4.0.tgz", - "integrity": "sha512-7TBazUdCKGV7svZ+gh7C8esAnweJoG+SvcF6Cjqj4l17zA2q1cMwx2JObSioubk317H+cjcHgP+7fTs60paulg==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.0.6.tgz", + "integrity": "sha512-Fid6dPcjwepTFraz0YxIMCi7dejjJ/KL9FBjPYhBp4Sv1Y9PdhImlKZqYU555BlN4TQKaTc+F2Av1z+anVyGkA==", "dev": true, "requires": { "detect-newline": "^3.0.0" } }, "jest-each": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.4.2.tgz", - "integrity": "sha512-53V2MNyW28CTruB3lXaHNk6PkiIFuzdOC9gR3C6j8YE/ACfrPnz+slB0s17AgU1TtxNzLuHyvNlLJ+8QYw9nBg==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.3.1.tgz", + "integrity": "sha512-E4SwfzKJWYcvOYCjOxhZcxwL+AY0uFMvdCOwvzgutJiaiodFjkxQQDxHm8FQBeTqDnSmKsQWn7ldMRzTn2zJaQ==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.2" + "jest-get-type": "^27.3.1", + "jest-util": "^27.3.1", + "pretty-format": "^27.3.1" } }, "jest-environment-jsdom": { - "version": "27.4.4", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.4.4.tgz", - "integrity": "sha512-cYR3ndNfHBqQgFvS1RL7dNqSvD//K56j/q1s2ygNHcfTCAp12zfIromO1w3COmXrxS8hWAh7+CmZmGCIoqGcGA==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.3.1.tgz", + "integrity": "sha512-3MOy8qMzIkQlfb3W1TfrD7uZHj+xx8Olix5vMENkj5djPmRqndMaXtpnaZkxmxM+Qc3lo+yVzJjzuXbCcZjAlg==", "dev": true, "requires": { - "@jest/environment": "^27.4.4", - "@jest/fake-timers": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/environment": "^27.3.1", + "@jest/fake-timers": "^27.3.1", + "@jest/types": "^27.2.5", "@types/node": "*", - "jest-mock": "^27.4.2", - "jest-util": "^27.4.2", + "jest-mock": "^27.3.0", + "jest-util": "^27.3.1", "jsdom": "^16.6.0" } }, "jest-environment-node": { - "version": "27.4.4", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.4.4.tgz", - "integrity": "sha512-D+v3lbJ2GjQTQR23TK0kY3vFVmSeea05giInI41HHOaJnAwOnmUHTZgUaZL+VxUB43pIzoa7PMwWtCVlIUoVoA==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.3.1.tgz", + "integrity": "sha512-T89F/FgkE8waqrTSA7/ydMkcc52uYPgZZ6q8OaZgyiZkJb5QNNCF6oPZjH9IfPFfcc9uBWh1574N0kY0pSvTXw==", "dev": true, "requires": { - "@jest/environment": "^27.4.4", - "@jest/fake-timers": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/environment": "^27.3.1", + "@jest/fake-timers": "^27.3.1", + "@jest/types": "^27.2.5", "@types/node": "*", - "jest-mock": "^27.4.2", - "jest-util": "^27.4.2" + "jest-mock": "^27.3.0", + "jest-util": "^27.3.1" } }, "jest-get-type": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz", - "integrity": "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.3.1.tgz", + "integrity": "sha512-+Ilqi8hgHSAdhlQ3s12CAVNd8H96ZkQBfYoXmArzZnOfAtVAJEiPDBirjByEblvG/4LPJmkL+nBqPO3A1YJAEg==", "dev": true }, "jest-haste-map": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.4.5.tgz", - "integrity": "sha512-oJm1b5qhhPs78K24EDGifWS0dELYxnoBiDhatT/FThgB9yxqUm5F6li3Pv+Q+apMBmmPNzOBnZ7ZxWMB1Leq1Q==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.3.1.tgz", + "integrity": "sha512-lYfNZIzwPccDJZIyk9Iz5iQMM/MH56NIIcGj7AFU1YyA4ewWFBl8z+YPJuSCRML/ee2cCt2y3W4K3VXPT6Nhzg==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "@types/graceful-fs": "^4.1.2", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "fsevents": "^2.3.2", "graceful-fs": "^4.2.4", - "jest-regex-util": "^27.4.0", - "jest-serializer": "^27.4.0", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.5", + "jest-regex-util": "^27.0.6", + "jest-serializer": "^27.0.6", + "jest-util": "^27.3.1", + "jest-worker": "^27.3.1", "micromatch": "^4.0.4", "walker": "^1.0.7" } }, "jest-jasmine2": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.4.5.tgz", - "integrity": "sha512-oUnvwhJDj2LhOiUB1kdnJjkx8C5PwgUZQb9urF77mELH9DGR4e2GqpWQKBOYXWs5+uTN9BGDqRz3Aeg5Wts7aw==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.3.1.tgz", + "integrity": "sha512-WK11ZUetDQaC09w4/j7o4FZDUIp+4iYWH/Lik34Pv7ukL+DuXFGdnmmi7dT58J2ZYKFB5r13GyE0z3NPeyJmsg==", "dev": true, "requires": { "@babel/traverse": "^7.1.0", - "@jest/environment": "^27.4.4", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/environment": "^27.3.1", + "@jest/source-map": "^27.0.6", + "@jest/test-result": "^27.3.1", + "@jest/types": "^27.2.5", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", - "expect": "^27.4.2", + "expect": "^27.3.1", "is-generator-fn": "^2.0.0", - "jest-each": "^27.4.2", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-runtime": "^27.4.5", - "jest-snapshot": "^27.4.5", - "jest-util": "^27.4.2", - "pretty-format": "^27.4.2", + "jest-each": "^27.3.1", + "jest-matcher-utils": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-runtime": "^27.3.1", + "jest-snapshot": "^27.3.1", + "jest-util": "^27.3.1", + "pretty-format": "^27.3.1", "throat": "^6.0.1" } }, "jest-leak-detector": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.4.2.tgz", - "integrity": "sha512-ml0KvFYZllzPBJWDei3mDzUhyp/M4ubKebX++fPaudpe8OsxUE+m+P6ciVLboQsrzOCWDjE20/eXew9QMx/VGw==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.3.1.tgz", + "integrity": "sha512-78QstU9tXbaHzwlRlKmTpjP9k4Pvre5l0r8Spo4SbFFVy/4Abg9I6ZjHwjg2QyKEAMg020XcjP+UgLZIY50yEg==", "dev": true, "requires": { - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.2" + "jest-get-type": "^27.3.1", + "pretty-format": "^27.3.1" } }, "jest-matcher-utils": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.4.2.tgz", - "integrity": "sha512-jyP28er3RRtMv+fmYC/PKG8wvAmfGcSNproVTW2Y0P/OY7/hWUOmsPfxN1jOhM+0u2xU984u2yEagGivz9OBGQ==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.3.1.tgz", + "integrity": "sha512-hX8N7zXS4k+8bC1Aj0OWpGb7D3gIXxYvPNK1inP5xvE4ztbz3rc4AkI6jGVaerepBnfWB17FL5lWFJT3s7qo8w==", "dev": true, "requires": { "chalk": "^4.0.0", - "jest-diff": "^27.4.2", - "jest-get-type": "^27.4.0", - "pretty-format": "^27.4.2" + "jest-diff": "^27.3.1", + "jest-get-type": "^27.3.1", + "pretty-format": "^27.3.1" } }, "jest-message-util": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.4.2.tgz", - "integrity": "sha512-OMRqRNd9E0DkBLZpFtZkAGYOXl6ZpoMtQJWTAREJKDOFa0M6ptB7L67tp+cszMBkvSgKOhNtQp2Vbcz3ZZKo/w==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.3.1.tgz", + "integrity": "sha512-bh3JEmxsTZ/9rTm0jQrPElbY2+y48Rw2t47uMfByNyUVR+OfPh4anuyKsGqsNkXk/TI4JbLRZx+7p7Hdt6q1yg==", "dev": true, "requires": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", "micromatch": "^4.0.4", - "pretty-format": "^27.4.2", + "pretty-format": "^27.3.1", "slash": "^3.0.0", "stack-utils": "^2.0.3" } }, "jest-mock": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.4.2.tgz", - "integrity": "sha512-PDDPuyhoukk20JrQKeofK12hqtSka7mWH0QQuxSNgrdiPsrnYYLS6wbzu/HDlxZRzji5ylLRULeuI/vmZZDrYA==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.3.0.tgz", + "integrity": "sha512-ziZiLk0elZOQjD08bLkegBzv5hCABu/c8Ytx45nJKkysQwGaonvmTxwjLqEA4qGdasq9o2I8/HtdGMNnVsMTGw==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "@types/node": "*" } }, @@ -7932,83 +7928,83 @@ "requires": {} }, "jest-regex-util": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.4.0.tgz", - "integrity": "sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.0.6.tgz", + "integrity": "sha512-SUhPzBsGa1IKm8hx2F4NfTGGp+r7BXJ4CulsZ1k2kI+mGLG+lxGrs76veN2LF/aUdGosJBzKgXmNCw+BzFqBDQ==", "dev": true }, "jest-resolve": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.4.5.tgz", - "integrity": "sha512-xU3z1BuOz/hUhVUL+918KqUgK+skqOuUsAi7A+iwoUldK6/+PW+utK8l8cxIWT9AW7IAhGNXjSAh1UYmjULZZw==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.3.1.tgz", + "integrity": "sha512-Dfzt25CFSPo3Y3GCbxynRBZzxq9AdyNN+x/v2IqYx6KVT5Z6me2Z/PsSGFSv3cOSUZqJ9pHxilao/I/m9FouLw==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "chalk": "^4.0.0", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.5", + "jest-haste-map": "^27.3.1", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", "resolve": "^1.20.0", "resolve.exports": "^1.1.0", "slash": "^3.0.0" } }, "jest-resolve-dependencies": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.4.5.tgz", - "integrity": "sha512-elEVvkvRK51y037NshtEkEnukMBWvlPzZHiL847OrIljJ8yIsujD2GXRPqDXC4rEVKbcdsy7W0FxoZb4WmEs7w==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.3.1.tgz", + "integrity": "sha512-X7iLzY8pCiYOnvYo2YrK3P9oSE8/3N2f4pUZMJ8IUcZnT81vlSonya1KTO9ZfKGuC+svE6FHK/XOb8SsoRUV1A==", "dev": true, "requires": { - "@jest/types": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-snapshot": "^27.4.5" + "@jest/types": "^27.2.5", + "jest-regex-util": "^27.0.6", + "jest-snapshot": "^27.3.1" } }, "jest-runner": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.4.5.tgz", - "integrity": "sha512-/irauncTfmY1WkTaRQGRWcyQLzK1g98GYG/8QvIPviHgO1Fqz1JYeEIsSfF+9mc/UTA6S+IIHFgKyvUrtiBIZg==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.3.1.tgz", + "integrity": "sha512-r4W6kBn6sPr3TBwQNmqE94mPlYVn7fLBseeJfo4E2uCTmAyDFm2O5DYAQAFP7Q3YfiA/bMwg8TVsciP7k0xOww==", "dev": true, "requires": { - "@jest/console": "^27.4.2", - "@jest/environment": "^27.4.4", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", + "@jest/console": "^27.3.1", + "@jest/environment": "^27.3.1", + "@jest/test-result": "^27.3.1", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", "@types/node": "*", "chalk": "^4.0.0", "emittery": "^0.8.1", "exit": "^0.1.2", "graceful-fs": "^4.2.4", - "jest-docblock": "^27.4.0", - "jest-environment-jsdom": "^27.4.4", - "jest-environment-node": "^27.4.4", - "jest-haste-map": "^27.4.5", - "jest-leak-detector": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-resolve": "^27.4.5", - "jest-runtime": "^27.4.5", - "jest-util": "^27.4.2", - "jest-worker": "^27.4.5", + "jest-docblock": "^27.0.6", + "jest-environment-jsdom": "^27.3.1", + "jest-environment-node": "^27.3.1", + "jest-haste-map": "^27.3.1", + "jest-leak-detector": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-resolve": "^27.3.1", + "jest-runtime": "^27.3.1", + "jest-util": "^27.3.1", + "jest-worker": "^27.3.1", "source-map-support": "^0.5.6", "throat": "^6.0.1" } }, "jest-runtime": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.4.5.tgz", - "integrity": "sha512-CIYqwuJQXHQtPd/idgrx4zgJ6iCb6uBjQq1RSAGQrw2S8XifDmoM1Ot8NRd80ooAm+ZNdHVwsktIMGlA1F1FAQ==", - "dev": true, - "requires": { - "@jest/console": "^27.4.2", - "@jest/environment": "^27.4.4", - "@jest/globals": "^27.4.4", - "@jest/source-map": "^27.4.0", - "@jest/test-result": "^27.4.2", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.3.1.tgz", + "integrity": "sha512-qtO6VxPbS8umqhEDpjA4pqTkKQ1Hy4ZSi9mDVeE9Za7LKBo2LdW2jmT+Iod3XFaJqINikZQsn2wEi0j9wPRbLg==", + "dev": true, + "requires": { + "@jest/console": "^27.3.1", + "@jest/environment": "^27.3.1", + "@jest/globals": "^27.3.1", + "@jest/source-map": "^27.0.6", + "@jest/test-result": "^27.3.1", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", "@types/yargs": "^16.0.0", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", @@ -8017,23 +8013,23 @@ "exit": "^0.1.2", "glob": "^7.1.3", "graceful-fs": "^4.2.4", - "jest-haste-map": "^27.4.5", - "jest-message-util": "^27.4.2", - "jest-mock": "^27.4.2", - "jest-regex-util": "^27.4.0", - "jest-resolve": "^27.4.5", - "jest-snapshot": "^27.4.5", - "jest-util": "^27.4.2", - "jest-validate": "^27.4.2", + "jest-haste-map": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-mock": "^27.3.0", + "jest-regex-util": "^27.0.6", + "jest-resolve": "^27.3.1", + "jest-snapshot": "^27.3.1", + "jest-util": "^27.3.1", + "jest-validate": "^27.3.1", "slash": "^3.0.0", "strip-bom": "^4.0.0", "yargs": "^16.2.0" } }, "jest-serializer": { - "version": "27.4.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.4.0.tgz", - "integrity": "sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ==", + "version": "27.0.6", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.0.6.tgz", + "integrity": "sha512-PtGdVK9EGC7dsaziskfqaAPib6wTViY3G8E5wz9tLVPhHyiDNTZn/xjZ4khAw+09QkoOVpn7vF5nPSN6dtBexA==", "dev": true, "requires": { "@types/node": "*", @@ -8041,9 +8037,9 @@ } }, "jest-snapshot": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.4.5.tgz", - "integrity": "sha512-eCi/iM1YJFrJWiT9de4+RpWWWBqsHiYxFG9V9o/n0WXs6GpW4lUt4FAHAgFPTLPqCUVzrMQmSmTZSgQzwqR7IQ==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.3.1.tgz", + "integrity": "sha512-APZyBvSgQgOT0XumwfFu7X3G5elj6TGhCBLbBdn3R1IzYustPGPE38F51dBWMQ8hRXa9je0vAdeVDtqHLvB6lg==", "dev": true, "requires": { "@babel/core": "^7.7.2", @@ -8052,23 +8048,23 @@ "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", "@babel/types": "^7.0.0", - "@jest/transform": "^27.4.5", - "@jest/types": "^27.4.2", + "@jest/transform": "^27.3.1", + "@jest/types": "^27.2.5", "@types/babel__traverse": "^7.0.4", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^27.4.2", + "expect": "^27.3.1", "graceful-fs": "^4.2.4", - "jest-diff": "^27.4.2", - "jest-get-type": "^27.4.0", - "jest-haste-map": "^27.4.5", - "jest-matcher-utils": "^27.4.2", - "jest-message-util": "^27.4.2", - "jest-resolve": "^27.4.5", - "jest-util": "^27.4.2", + "jest-diff": "^27.3.1", + "jest-get-type": "^27.3.1", + "jest-haste-map": "^27.3.1", + "jest-matcher-utils": "^27.3.1", + "jest-message-util": "^27.3.1", + "jest-resolve": "^27.3.1", + "jest-util": "^27.3.1", "natural-compare": "^1.4.0", - "pretty-format": "^27.4.2", + "pretty-format": "^27.3.1", "semver": "^7.3.2" }, "dependencies": { @@ -8084,12 +8080,12 @@ } }, "jest-util": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.4.2.tgz", - "integrity": "sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.3.1.tgz", + "integrity": "sha512-8fg+ifEH3GDryLQf/eKZck1DEs2YuVPBCMOaHQxVVLmQwl/CDhWzrvChTX4efLZxGrw+AA0mSXv78cyytBt/uw==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -8098,46 +8094,46 @@ } }, "jest-validate": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.2.tgz", - "integrity": "sha512-hWYsSUej+Fs8ZhOm5vhWzwSLmVaPAxRy+Mr+z5MzeaHm9AxUpXdoVMEW4R86y5gOobVfBsMFLk4Rb+QkiEpx1A==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.3.1.tgz", + "integrity": "sha512-3H0XCHDFLA9uDII67Bwi1Vy7AqwA5HqEEjyy934lgVhtJ3eisw6ShOF1MDmRPspyikef5MyExvIm0/TuLzZ86Q==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^27.4.0", + "jest-get-type": "^27.3.1", "leven": "^3.1.0", - "pretty-format": "^27.4.2" + "pretty-format": "^27.3.1" }, "dependencies": { "camelcase": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.1.tgz", - "integrity": "sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", "dev": true } } }, "jest-watcher": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.4.2.tgz", - "integrity": "sha512-NJvMVyyBeXfDezhWzUOCOYZrUmkSCiatpjpm+nFUid74OZEHk6aMLrZAukIiFDwdbqp6mTM6Ui1w4oc+8EobQg==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.3.1.tgz", + "integrity": "sha512-9/xbV6chABsGHWh9yPaAGYVVKurWoP3ZMCv6h+O1v9/+pkOroigs6WzZ0e9gLP/njokUwM7yQhr01LKJVMkaZA==", "dev": true, "requires": { - "@jest/test-result": "^27.4.2", - "@jest/types": "^27.4.2", + "@jest/test-result": "^27.3.1", + "@jest/types": "^27.2.5", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "jest-util": "^27.4.2", + "jest-util": "^27.3.1", "string-length": "^4.0.1" } }, "jest-worker": { - "version": "27.4.5", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.5.tgz", - "integrity": "sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.3.1.tgz", + "integrity": "sha512-ks3WCzsiZaOPJl/oMsDjaf0TRiSv7ctNgs0FqRr2nARsovz6AWWy4oLElwcquGSz692DzgZQrCLScPNs5YlC4g==", "dev": true, "requires": { "@types/node": "*", @@ -8341,16 +8337,16 @@ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" + "version": "1.48.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", + "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==" }, "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "version": "2.1.31", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", + "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", "requires": { - "mime-db": "1.51.0" + "mime-db": "1.48.0" } }, "mimic-fn": { @@ -8375,23 +8371,16 @@ "dev": true }, "mongodb": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.7.3.tgz", - "integrity": "sha512-Psm+g3/wHXhjBEktkxXsFMZvd3nemI0r3IPsE0bU+4//PnvNWKkzhZcEsbPcYiWqe8XqXJJEg4Tgtr7Raw67Yw==", + "version": "3.6.9", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.9.tgz", + "integrity": "sha512-1nSCKgSunzn/CXwgOWgbPHUWOO5OfERcuOWISmqd610jn0s8BU9K4879iJVabqgpPPbA6hO7rG48eq+fGED3Mg==", "requires": { "bl": "^2.2.1", "bson": "^1.1.4", "denque": "^1.4.1", - "optional-require": "^1.1.8", + "optional-require": "^1.0.3", "safe-buffer": "^5.1.2", "saslprep": "^1.0.0" - }, - "dependencies": { - "bson": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.6.tgz", - "integrity": "sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg==" - } } }, "ms": { @@ -8416,6 +8405,12 @@ "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", "dev": true }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, "node-releases": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz", @@ -8449,9 +8444,9 @@ "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-inspect": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.1.tgz", - "integrity": "sha512-If7BjFlpkzzBeV1cqgT3OSWT3azyoxDGajR+iGnFBfVV2EWyDyWaZZW2ERDjUaY2QM8i5jI3Sj7mhsM4DDAqWA==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", + "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", "dev": true }, "on-finished": { @@ -8481,12 +8476,9 @@ } }, "optional-require": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.1.8.tgz", - "integrity": "sha512-jq83qaUb0wNg9Krv1c5OQ+58EK+vHde6aBPzLvPPqJm89UQWsvSuFy9X/OSNJnFeSOKo7btE0n8Nl2+nE+z5nA==", - "requires": { - "require-at": "^1.0.6" - } + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/optional-require/-/optional-require-1.0.3.tgz", + "integrity": "sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA==" }, "optionator": { "version": "0.8.3", @@ -8579,10 +8571,13 @@ "dev": true }, "pirates": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz", - "integrity": "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw==", - "dev": true + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "requires": { + "node-modules-regexp": "^1.0.0" + } }, "pkg-dir": { "version": "4.2.0", @@ -8600,12 +8595,12 @@ "dev": true }, "pretty-format": { - "version": "27.4.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.2.tgz", - "integrity": "sha512-p0wNtJ9oLuvgOQDEIZ9zQjZffK7KtyR6Si0jnXULIDwrlNF8Cuir3AZP0hHv0jmKuNN/edOnbMjnzd4uTcmWiw==", + "version": "27.3.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.3.1.tgz", + "integrity": "sha512-DR/c+pvFc52nLimLROYjnXPtolawm+uWDxr4FjuLDLUn+ktWnSN851KoHwHzzqq6rfCOjkzN8FLgDrSub6UDuA==", "dev": true, "requires": { - "@jest/types": "^27.4.2", + "@jest/types": "^27.2.5", "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", "react-is": "^17.0.1" @@ -8725,11 +8720,6 @@ "redis-errors": "^1.0.0" } }, - "require-at": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/require-at/-/require-at-1.0.6.tgz", - "integrity": "sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g==" - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -8880,9 +8870,9 @@ } }, "signal-exit": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", - "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz", + "integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ==", "dev": true }, "sisteransi": { @@ -8904,9 +8894,9 @@ "dev": true }, "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==", + "version": "0.5.20", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz", + "integrity": "sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw==", "dev": true, "requires": { "buffer-from": "^1.0.0", @@ -9012,9 +9002,9 @@ }, "dependencies": { "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { "ms": "2.1.2" @@ -9033,9 +9023,9 @@ "dev": true }, "qs": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.2.tgz", - "integrity": "sha512-mSIdjzqznWgfd4pMii7sHtaYF8rx8861hBO80SraY5GT0XQibWZWJSid0avzHGkDIZLImux2S5mXO0Hfct2QCw==", + "version": "6.10.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz", + "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==", "dev": true, "requires": { "side-channel": "^1.0.4" @@ -9185,9 +9175,9 @@ } }, "ts-jest": { - "version": "27.1.1", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.1.tgz", - "integrity": "sha512-Ds0VkB+cB+8g2JUmP/GKWndeZcCKrbe6jzolGrVWdqVUFByY/2KDHqxJ7yBSon7hDB1TA4PXxjfZ+JjzJisvgA==", + "version": "27.0.7", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.0.7.tgz", + "integrity": "sha512-O41shibMqzdafpuP+CkrOL7ykbmLh+FqQrXEmV9CydQ5JBk0Sj0uAEF5TNNe94fZWKm3yYvWa/IbyV4Yg1zK2Q==", "dev": true, "requires": { "bs-logger": "0.x", @@ -9279,9 +9269,9 @@ } }, "typescript": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz", - "integrity": "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==", + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.2.tgz", + "integrity": "sha512-zZ4hShnmnoVnAHpVHWpTcxdv7dWP60S2FsydQLV8V5PbS3FifjWFFRiHSWpDJahly88PRyV5teTSLoq4eG7mKw==", "dev": true }, "universalify": { @@ -9433,9 +9423,9 @@ } }, "ws": { - "version": "7.5.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz", - "integrity": "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz", + "integrity": "sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w==", "dev": true, "requires": {} }, diff --git a/api/package.json b/api/package.json index c789ceef6..97e3a8bbe 100644 --- a/api/package.json +++ b/api/package.json @@ -1,6 +1,6 @@ { "name": "panic-api", - "version": "1.1.0", + "version": "1.1.1", "description": "API for querying PANIC data.", "main": "server.js", "scripts": { diff --git a/api/src/server/redis.ts b/api/src/server/redis.ts index 7b19adf74..7a4e4ae87 100644 --- a/api/src/server/redis.ts +++ b/api/src/server/redis.ts @@ -57,7 +57,7 @@ export const getChainlinkNodeKeys = (): ChainlinkNodeKeys => ({ no_of_unconfirmed_txs: 'cl7', total_errored_job_runs: 'cl8', current_gas_price_info: 'cl9', - eth_balance_info: 'cl10', + balance_info: 'cl10', went_down_at_prometheus: 'cl11', last_prometheus_source_used: 'cl12', last_monitored_prometheus: 'cl13', @@ -106,8 +106,8 @@ export const getAlertKeysNode = (): AlertKeysNode => ({ cl_tx_manager_gas_bump_exceeds_limit_total: `${alertKeysClNodePrefix}5`, cl_unconfirmed_transactions: `${alertKeysClNodePrefix}6`, cl_run_status_update_total: `${alertKeysClNodePrefix}7`, - cl_eth_balance_amount: `${alertKeysClNodePrefix}8`, - cl_eth_balance_amount_increase: `${alertKeysClNodePrefix}9`, + cl_balance_amount: `${alertKeysClNodePrefix}8`, + cl_balance_amount_increase: `${alertKeysClNodePrefix}9`, cl_invalid_url: `${alertKeysClNodePrefix}10`, cl_metric_not_found: `${alertKeysClNodePrefix}11`, cl_node_is_down: `${alertKeysClNodePrefix}12`, diff --git a/api/src/server/types.ts b/api/src/server/types.ts index 5aaa2ed76..c7383b81a 100644 --- a/api/src/server/types.ts +++ b/api/src/server/types.ts @@ -49,7 +49,7 @@ export interface ChainlinkNodeKeys { no_of_unconfirmed_txs: string, total_errored_job_runs: string, current_gas_price_info: string, - eth_balance_info: string, + balance_info: string, went_down_at_prometheus: string, last_prometheus_source_used: string, last_monitored_prometheus: string, @@ -97,8 +97,8 @@ export interface AlertKeysNode { cl_tx_manager_gas_bump_exceeds_limit_total: string, cl_unconfirmed_transactions: string, cl_run_status_update_total: string, - cl_eth_balance_amount: string, - cl_eth_balance_amount_increase: string, + cl_balance_amount: string, + cl_balance_amount_increase: string, cl_invalid_url: string, cl_metric_not_found: string, cl_node_is_down: string, diff --git a/api/src/swagger.json b/api/src/swagger.json index a099089d5..ad77779d6 100644 --- a/api/src/swagger.json +++ b/api/src/swagger.json @@ -1,7 +1,7 @@ { "openapi": "3.0.1", "info": { - "version": "1.1.0", + "version": "1.1.1", "title": "PANIC API", "description": "Endpoints to query Redis and Mongodb for Alerts and Metrics.", "license": { diff --git a/api/tests/server/redis.test.ts b/api/tests/server/redis.test.ts index 93d68b16e..6094819f1 100644 --- a/api/tests/server/redis.test.ts +++ b/api/tests/server/redis.test.ts @@ -99,7 +99,7 @@ describe('getChainlinkNodeKeys', () => { no_of_unconfirmed_txs: 'cl7', total_errored_job_runs: 'cl8', current_gas_price_info: 'cl9', - eth_balance_info: 'cl10', + balance_info: 'cl10', went_down_at_prometheus: 'cl11', last_prometheus_source_used: 'cl12', last_monitored_prometheus: 'cl13', @@ -155,8 +155,8 @@ describe('getAlertKeysNode', () => { cl_tx_manager_gas_bump_exceeds_limit_total: `${alertKeysClNodePrefix}5`, cl_unconfirmed_transactions: `${alertKeysClNodePrefix}6`, cl_run_status_update_total: `${alertKeysClNodePrefix}7`, - cl_eth_balance_amount: `${alertKeysClNodePrefix}8`, - cl_eth_balance_amount_increase: `${alertKeysClNodePrefix}9`, + cl_balance_amount: `${alertKeysClNodePrefix}8`, + cl_balance_amount_increase: `${alertKeysClNodePrefix}9`, cl_invalid_url: `${alertKeysClNodePrefix}10`, cl_metric_not_found: `${alertKeysClNodePrefix}11`, cl_node_is_down: `${alertKeysClNodePrefix}12`, diff --git a/docker-compose-tests.yml b/docker-compose-tests.yml index 1773802ec..4df4952cf 100644 --- a/docker-compose-tests.yml +++ b/docker-compose-tests.yml @@ -85,7 +85,7 @@ services: build: context: './' dockerfile: './alerter/Tests_Dockerfile' - image: 'simplyvc/panic_alerter_tests:1.1.0' + image: 'simplyvc/panic_alerter_tests:1.1.1' logging: driver: "json-file" options: diff --git a/docker-compose.yml b/docker-compose.yml index dfa53977a..e49398fae 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -18,7 +18,7 @@ services: build: context: './' dockerfile: './web-installer/Dockerfile' - image: 'simplyvc/panic_installer:1.1.0' + image: 'simplyvc/panic_installer:1.1.1' logging: driver: "json-file" options: @@ -120,7 +120,7 @@ services: build: context: './' dockerfile: './alerter/Alerter_Dockerfile' - image: 'simplyvc/panic_alerter:1.1.0' + image: 'simplyvc/panic_alerter:1.1.1' logging: driver: "json-file" options: @@ -181,7 +181,7 @@ services: build: context: './' dockerfile: './alerter/Health_Checker_Dockerfile' - image: 'simplyvc/alerter_health_checker:1.1.0' + image: 'simplyvc/alerter_health_checker:1.1.1' logging: driver: "json-file" options: @@ -214,7 +214,7 @@ services: build: context: './' dockerfile: './api/Dockerfile' - image: 'simplyvc/panic_api:1.1.0' + image: 'simplyvc/panic_api:1.1.1' volumes: - './config:/opt/panic/config' - './certificates:/opt/panic/certificates' @@ -235,7 +235,7 @@ services: args: - API_PORT - UI_DASHBOARD_PORT - image: 'simplyvc/panic_ui:1.1.0' + image: 'simplyvc/panic_ui:1.1.1' volumes: - './certificates:/opt/panic/certificates' ports: diff --git a/docs/CHANGE_LOG.md b/docs/CHANGE_LOG.md index 5b32b6bf8..cf35d3ad2 100644 --- a/docs/CHANGE_LOG.md +++ b/docs/CHANGE_LOG.md @@ -1,5 +1,12 @@ # Change Log +## 1.1.1 +Released on 17th May 2022 + +- Updated Chainlink Node Monitor/Alerts to use correct moniker for the balance of node accounts. +- Integrated System Alerter with current factory classes. +- Fixed colored severities in systems-overview page in UI. + ## 1.1.0 Released on 28th April 2022 diff --git a/docs/DESIGN_AND_FEATURES.md b/docs/DESIGN_AND_FEATURES.md index 1ad45e70f..30efa0b39 100644 --- a/docs/DESIGN_AND_FEATURES.md +++ b/docs/DESIGN_AND_FEATURES.md @@ -192,16 +192,16 @@ In the lists below we will show which alerts have severity thresholds and which | `NoOfUnconfirmedTxsDecreasedBelowThresholdAlert` | | `INFO` | ✗ | Depends on `NoOfUnconfirmedTxsIncreasedAboveThresholdAlert` | The number of unconfirmed transactions have decreased below `warning` or `critical` thresholds. | | `TotalErroredJobRunsIncreasedAboveThresholdAlert` | `WARNING`,`CRITICAL` | | ✓ | ✓ | The number of total errored job runs increased above `warning` or `critical` thresholds. | | `TotalErroredJobRunsDecreasedBelowThresholdAlert` | | `INFO` | ✗ | Depends on `TotalErroredJobRunsIncreasedAboveThresholdAlert` | The number of total errored jobs run decreases below `warning` or `critical` thresholds. | -| `EthBalanceIncreasedAboveThresholdAlert` | | `INFO` | ✓ | Depends on `EthBalanceDecreasedBelowThresholdAlert` | The Ethereum balance increases above `warning` or `critical` thresholds. | -| `EthBalanceDecreasedBelowThresholdAlert` | `WARNING`,`CRITICAL` | | ✓ | ✓ | The Ethereum balance decreases below `warning` or `critical` thresholds`. | -| `EthBalanceToppedUpAlert` | | `INFO` | ✓ | ✓ | The Ethereum balance is topped up this alert is raised. | +| `BalanceIncreasedAboveThresholdAlert` | | `INFO` | ✓ | Depends on `BalanceDecreasedBelowThresholdAlert` | The account balance increases above `warning` or `critical` thresholds. | +| `BalanceDecreasedBelowThresholdAlert` | `WARNING`,`CRITICAL` | | ✓ | ✓ | The account balance decreases below `warning` or `critical` thresholds`. | +| `BalanceToppedUpAlert` | | `INFO` | ✓ | ✓ | The account balance is topped up this alert is raised. | | `InvalidUrlAlert` | | `ERROR` | ✗ | ✗ | The URL is unreachable most likely due to an invalid configuration. | | `ValidUrlAlert` | | `INFO` | ✗ | ✗ | The monitors manage to connect to a valid URL. | | `PrometheusSourceIsDownAlert` | | `WARNING` | ✗ | ✗ | The URL given for the prometheus endpoint is unreachable. | | `PrometheusSourceBackUpAgainAlert` | | `INFO` | ✗ | ✗ | The URL given for the prometheus endpoint is now reachable after being unreachable. | | `NodeWentDownAtAlert` | `WARNING`,`CRITICAL` | | ✓ | ✓ | All endpoints of a node are unreachable, classifying the node as down. | | `NodeBackUpAgainAlert` | | `INFO` | ✗ | Depends on `NodeWentDownAtAlert` | Valid endpoints have been found meaning that the node is now reachable. | -| `NodeStillDownAlert` | | `CRITICAL` | ✓ | ✓ but depends on `NodeWentDownAtAlert` | If a node has been classified as down for sometime this alert will keep repeating for a period until it is back up again. | +| `NodeStillDownAlert` | | `CRITICAL` | ✗ | Depends on `NodeWentDownAtAlert` | If a node has been classified as down for sometime this alert will keep repeating for a period until it is back up again. | | `MetricNotFoundErrorAlert` | | `ERROR` | ✗ | ✗ | The endpoint had it's prometheus data changed therefore PANIC cannot find the correct metrics to read. Either the wrong endpoint was given or PANIC needs updating. | | `MetricFoundAlert` | | `INFO` | ✗ | ✗ | This is raised when the `MetricNotFoundErrorAlert` was raised for whatever reason and now PANIC has managed to locate the metric at the prometheus endpoint. | @@ -247,8 +247,8 @@ In the lists below we will show which alerts have severity thresholds and which | `ValidatorIsActiveAlert` | | `INFO` | ✗ | Depends on `ValidatorIsNotActiveAlert` | Validator is active in the current consensus session after not being active in a previous consensus session. | | `ValidatorIsJailedAlert` | | `CRITICAL` | ✓ | ✓ | Validator is jailed. | | `ValidatorIsNoLongerJailedAlert` | | `INFO` | ✗ | Depends on `ValidatorIsJailedAlert` | Validator is no longer jailed. | -| `BlocksMissedIncreasedAboveThresholdAlert` | `WARNING`,`CRITICAL` | | ✓ | ✓ | The number of missed block signatures increased above `warning` or `critical` thresholds. | -| `BlocksMissedDecreasedBelowThresholdAlert` | `INFO` | | ✗ | Depends on `BlocksMissedIncreasedAboveThresholdAlert` | The number of missed block signatures decreased below `warning` or `critical` thresholds. | +| `BlocksMissedIncreasedAboveThresholdAlert` | `WARNING`,`CRITICAL` | | ✓ | ✓ | The number of missed block signatures increased above `warning` or `critical` thresholds. | +| `BlocksMissedDecreasedBelowThresholdAlert` | `INFO` | | ✗ | Depends on `BlocksMissedIncreasedAboveThresholdAlert` | The number of missed block signatures decreased below `warning` or `critical` thresholds. | | `NoChangeInHeightAlert` | `WARNING`,`CRITICAL` | | ✓ | ✓ | There hasn't been a change in node block height over a period of time. | | `BlockHeightUpdatedAlert` | `INFO` | | ✗ | Depends on `BlockHeightUpdatedAlert` | Cosmos node starts to update it's block height. | | `BlockHeightDifferenceIncreasedAboveThresholdAlert` | `WARNING`,`CRITICAL` | | ✓ | ✓ | The block height difference between multiple Cosmos nodes increased above thresholds. | diff --git a/scripts/README.md b/scripts/README.md index 87d8528df..39590035c 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -54,4 +54,16 @@ scripts/clean_ui.sh ``` scripts/reset_rabbit.sh -``` \ No newline at end of file +``` + +## Reset Redis + +``` +scripts/reset_redis.sh +``` + +## Upgrade to version 1.1.1 from an older version + +``` +scripts/upgrade_to_1_1_1.sh +``` diff --git a/scripts/reset_redis.sh b/scripts/reset_redis.sh new file mode 100755 index 000000000..45d26cd4f --- /dev/null +++ b/scripts/reset_redis.sh @@ -0,0 +1,4 @@ +#!/bin/bash +docker-compose kill redis +docker-compose rm -v redis +docker-compose up --build -d redis \ No newline at end of file diff --git a/scripts/upgrade_to_1_1_1.sh b/scripts/upgrade_to_1_1_1.sh new file mode 100755 index 000000000..e4baab112 --- /dev/null +++ b/scripts/upgrade_to_1_1_1.sh @@ -0,0 +1,14 @@ +filepath="config/chains" +searchstring="eth_balance_amount" +replacestring="balance_amount" + +for file in $(grep -l -R $searchstring $filepath) +do + sed -e "s/$searchstring/$replacestring/ig" $file > tempfile.tmp + mv tempfile.tmp $file + chmod 755 $file + + echo "Modified: " $file +done + +source scripts/reset_redis.sh \ No newline at end of file diff --git a/ui/Dockerfile b/ui/Dockerfile index 0ee075aa1..a9e694d73 100644 --- a/ui/Dockerfile +++ b/ui/Dockerfile @@ -6,6 +6,9 @@ ARG UI_DASHBOARD_PORT ENV API_PORT=$API_PORT ENV UI_DASHBOARD_PORT=$UI_DASHBOARD_PORT +# This should be set to false for development on non-ARM systems +ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true + # Create app directory WORKDIR /opt/panic diff --git a/ui/README.md b/ui/README.md index 5dfcffb5e..4c4dfa15c 100644 --- a/ui/README.md +++ b/ui/README.md @@ -125,6 +125,14 @@ right-hand side of the header, and choosing the desired base-chain. Firefox you must accept the certificates on both `https://{UI_ACCESS_IP}:UI_PORT` and `https://{UI_ACCESS_IP}:API_PORT`. More information regarding this issue can be found [here](https://stackoverflow.com/questions/51831652/cors-request-across-different-ports-did-not-succeed-on-firefox-but-works-on-chro). +- Similarly to the above, certificate validation cannot be bypassed in some cases when accessing + PANIC UI from Chromium-based browsers. To bypass this check, click anywhere on the screen and + type `thisisunsafe`. More information regarding this issue can be found + [here](https://stackoverflow.com/questions/58802767/no-proceed-anyway-option-on-neterr-cert-invalid-in-chrome-on-macos). +- Due to an unavailable arm64 chromium binary used by puppeteer, by default, we + set the `PUPPETEER_SKIP_CHROMIUM_DOWNLOAD` ENV variable to `true` in the + Dockerfile for PANIC UI. This should be set to `false` for UI development on + non-ARM systems while chromium should be manually installed on ARM systems. --- [Back to front page](../README.md) \ No newline at end of file diff --git a/ui/package-lock.json b/ui/package-lock.json index 0c8f222cb..43c418ea3 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,12 +1,12 @@ { "name": "panic-ui", - "version": "1.1.0", + "version": "1.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "panic-ui", - "version": "1.1.0", + "version": "1.1.1", "license": "MIT", "dependencies": { "@simply-vc/uikit": "~1.2.0" diff --git a/ui/package.json b/ui/package.json index a39d37b50..bd384c7b6 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,7 +1,7 @@ { "name": "panic-ui", "private": true, - "version": "1.1.0", + "version": "1.1.1", "description": "PANIC UI", "author": "Simply-VC", "scripts": { diff --git a/ui/src/components/panic-alerts-overview/panic-alerts-overview.tsx b/ui/src/components/panic-alerts-overview/panic-alerts-overview.tsx index 3e91c1237..a047f9b3b 100644 --- a/ui/src/components/panic-alerts-overview/panic-alerts-overview.tsx +++ b/ui/src/components/panic-alerts-overview/panic-alerts-overview.tsx @@ -102,6 +102,10 @@ export class PanicAlertsOverview implements PanicAlertsOverviewInterface { } } + disconnectedCallback() { + window.clearInterval(this._updater); + } + render() { return ( diff --git a/ui/src/utils/metrics.ts b/ui/src/utils/metrics.ts index a7cd14db1..28469924c 100644 --- a/ui/src/utils/metrics.ts +++ b/ui/src/utils/metrics.ts @@ -139,6 +139,7 @@ async function getMetricAlerts(chains: SubChain[]): Promise { let chainSources = {parentIds: {}}; for (const chain of chains) { chainSources.parentIds[chain.id] = { + include_chain_sourced_alerts: false, systems: chain.systems.map((source) => {return source.id}), nodes: [], github_repos: [], @@ -181,11 +182,11 @@ function parseMetricAlerts(problems: any): MetricAlert[] { for (const source in problems) { for (const alert of problems[source]) { if (alert.severity in Severity) { - if (alert.metric in SystemMetricKeys) { + if (alert.metric.toUpperCase() in SystemMetricKeys) { metricAlerts.push({ origin: source, severity: alert.severity as Severity, - metric: alert.metric as SystemMetricKeys + metric: alert.metric.toUpperCase() as SystemMetricKeys }); } } else { diff --git a/web-installer/package-lock.json b/web-installer/package-lock.json index cce498387..87eb8918b 100644 --- a/web-installer/package-lock.json +++ b/web-installer/package-lock.json @@ -1,12 +1,12 @@ { "name": "webinstaller", - "version": "1.1.0", + "version": "1.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "webinstaller", - "version": "1.1.0", + "version": "1.1.1", "license": "Apache 2.0", "dependencies": { "@material-ui/core": "^4.11.0", @@ -57,11 +57,12 @@ } }, "node_modules/@ampproject/remapping": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", - "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.0" + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" }, "engines": { "node": ">=6.0.0" @@ -79,32 +80,32 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", - "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz", + "integrity": "sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.17.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz", - "integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.10.tgz", + "integrity": "sha512-liKoppandF3ZcBnIYFjfSDHZLKdLHGJRkoWtG8zQyGJBQfIYobpnVGI5+pLBNtS6psFLDzyq8+h5HiVljW9PNA==", "dependencies": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.17.2", - "@babel/parser": "^7.17.3", + "@babel/generator": "^7.17.10", + "@babel/helper-compilation-targets": "^7.17.10", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helpers": "^7.17.9", + "@babel/parser": "^7.17.10", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0", + "@babel/traverse": "^7.17.10", + "@babel/types": "^7.17.10", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", + "json5": "^2.2.1", "semver": "^6.3.0" }, "engines": { @@ -116,13 +117,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", - "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.10.tgz", + "integrity": "sha512-46MJZZo9y3o4kmhBVc7zW7i8dtR1oIK/sdO5NcfcZRhTGYi+KKJRtHNgsU6c4VUcJmUNV/LQdebD/9Dlv4K+Tg==", "dependencies": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/types": "^7.17.10", + "@jridgewell/gen-mapping": "^0.1.0", + "jsesc": "^2.5.1" }, "engines": { "node": ">=6.9.0" @@ -152,13 +153,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", - "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.10.tgz", + "integrity": "sha512-gh3RxjWbauw/dFiU/7whjd0qN9K6nPJMqe6+Er7rOavFh0CQUSwhAE3IcTho2rywPJFxej6TUUHDkWcYI6gGqQ==", "dependencies": { - "@babel/compat-data": "^7.16.4", + "@babel/compat-data": "^7.17.10", "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.17.5", + "browserslist": "^4.20.2", "semver": "^6.3.0" }, "engines": { @@ -169,14 +170,14 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz", - "integrity": "sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.9.tgz", + "integrity": "sha512-kUjip3gruz6AJKOq5i3nC6CoCEEF/oHH3cp6tOZhB+IyyyPyW0g1Gfsxn3mkk6S08pIA2y8GQh609v9G/5sHVQ==", "dependencies": { "@babel/helper-annotate-as-pure": "^7.16.7", "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-member-expression-to-functions": "^7.17.7", "@babel/helper-optimise-call-expression": "^7.16.7", "@babel/helper-replace-supers": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7" @@ -244,24 +245,12 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", + "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", "dependencies": { - "@babel/helper-get-function-arity": "^7.16.7", "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" }, "engines": { "node": ">=6.9.0" @@ -279,11 +268,11 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz", + "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" }, "engines": { "node": ">=6.9.0" @@ -301,13 +290,13 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz", - "integrity": "sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz", + "integrity": "sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw==", "dependencies": { "@babel/helper-environment-visitor": "^7.16.7", "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", "@babel/helper-split-export-declaration": "^7.16.7", "@babel/helper-validator-identifier": "^7.16.7", "@babel/template": "^7.16.7", @@ -366,11 +355,11 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", - "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz", + "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==", "dependencies": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" }, "engines": { "node": ">=6.9.0" @@ -429,12 +418,12 @@ } }, "node_modules/@babel/helpers": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", - "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.9.tgz", + "integrity": "sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q==", "dependencies": { "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", + "@babel/traverse": "^7.17.9", "@babel/types": "^7.17.0" }, "engines": { @@ -442,9 +431,9 @@ } }, "node_modules/@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.9.tgz", + "integrity": "sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg==", "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", @@ -455,9 +444,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", - "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.10.tgz", + "integrity": "sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ==", "bin": { "parser": "bin/babel-parser.js" }, @@ -543,13 +532,14 @@ } }, "node_modules/@babel/plugin-proposal-decorators": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.2.tgz", - "integrity": "sha512-WH8Z95CwTq/W8rFbMqb9p3hicpt4RX4f0K659ax2VHxgOyT6qQmUaEVEjIh4WR9Eh9NymkVn5vwsrE68fAQNUw==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.9.tgz", + "integrity": "sha512-EfH2LZ/vPa2wuPwJ26j+kYRkaubf89UlwxKXtxqEm57HrgSEYDB8t4swFP+p8LcI9yiP9ZRJJjo/58hS6BnaDA==", "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.17.1", + "@babel/helper-create-class-features-plugin": "^7.17.9", "@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", "@babel/plugin-syntax-decorators": "^7.17.0", "charcodes": "^0.2.0" }, @@ -974,9 +964,9 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", - "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.17.10.tgz", + "integrity": "sha512-xJefea1DWXW09pW4Tm9bjwVlPDyYA2it3fWlmEjpYz6alPvTUjL0EOzNzI/FEOyI3r4/J7uVH5UqKgl1TQ5hqQ==", "dependencies": { "@babel/helper-plugin-utils": "^7.16.7" }, @@ -1081,9 +1071,9 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz", - "integrity": "sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz", + "integrity": "sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ==", "dependencies": { "@babel/helper-plugin-utils": "^7.16.7" }, @@ -1228,13 +1218,13 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", - "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.9.tgz", + "integrity": "sha512-2TBFd/r2I6VlYn0YRTz2JdazS+FoUuQ2rIFHoAxtyP/0G3D82SBLaRq9rnUkpqlLg03Byfl/+M32mpxjO6KaPw==", "dependencies": { - "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-module-transforms": "^7.17.7", "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", "babel-plugin-dynamic-import-node": "^2.3.3" }, "engines": { @@ -1245,12 +1235,12 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", - "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.8.tgz", + "integrity": "sha512-39reIkMTUVagzgA5x88zDYXPCMT6lcaRKs1+S9K6NKBPErbgO/w/kP8GlNQTC87b412ZTlmNgr3k2JrWgHH+Bw==", "dependencies": { "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-module-transforms": "^7.17.7", "@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-validator-identifier": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" @@ -1278,11 +1268,11 @@ } }, "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", - "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.17.10.tgz", + "integrity": "sha512-v54O6yLaJySCs6mGzaVOUw9T967GnH38T6CQSAtnzdNPwu84l2qAjssKzo/WSO8Yi7NF+7ekm5cVbF/5qiIgNA==", "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.17.0" }, "engines": { "node": ">=6.9.0" @@ -1424,11 +1414,11 @@ } }, "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", - "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.17.9.tgz", + "integrity": "sha512-Lc2TfbxR1HOyn/c6b4Y/b6NHoTb67n/IoWLxTu4kC7h4KQnWlhCq2S8Tx0t2SVvv5Uu87Hs+6JEJ5kt2tYGylQ==", "dependencies": { - "regenerator-transform": "^0.14.2" + "regenerator-transform": "^0.15.0" }, "engines": { "node": ">=6.9.0" @@ -1452,9 +1442,9 @@ } }, "node_modules/@babel/plugin-transform-runtime": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.17.0.tgz", - "integrity": "sha512-fr7zPWnKXNc1xoHfrIU9mN/4XKX4VLZ45Q+oMhfsYIaHvg7mHgmhfOy/ckRWqDK7XF3QDigRpkh5DKq6+clE8A==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.17.10.tgz", + "integrity": "sha512-6jrMilUAJhktTr56kACL8LnWC5hx3Lf27BS0R0DSyW/OoJfb/iTHeE96V3b1dgKG3FSFdd/0culnYWMkjcKCig==", "dependencies": { "@babel/helper-module-imports": "^7.16.7", "@babel/helper-plugin-utils": "^7.16.7", @@ -1587,26 +1577,26 @@ } }, "node_modules/@babel/preset-env": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", - "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.17.10.tgz", + "integrity": "sha512-YNgyBHZQpeoBSRBg0xixsZzfT58Ze1iZrajvv0lJc70qDDGuGfonEnMGfWeSY0mQ3JTuCWFbMkzFRVafOyJx4g==", "dependencies": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", + "@babel/compat-data": "^7.17.10", + "@babel/helper-compilation-targets": "^7.17.10", "@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-validator-option": "^7.16.7", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", "@babel/plugin-proposal-async-generator-functions": "^7.16.8", "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", + "@babel/plugin-proposal-class-static-block": "^7.17.6", "@babel/plugin-proposal-dynamic-import": "^7.16.7", "@babel/plugin-proposal-export-namespace-from": "^7.16.7", "@babel/plugin-proposal-json-strings": "^7.16.7", "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", + "@babel/plugin-proposal-object-rest-spread": "^7.17.3", "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", "@babel/plugin-proposal-optional-chaining": "^7.16.7", "@babel/plugin-proposal-private-methods": "^7.16.11", @@ -1632,7 +1622,7 @@ "@babel/plugin-transform-block-scoping": "^7.16.7", "@babel/plugin-transform-classes": "^7.16.7", "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", + "@babel/plugin-transform-destructuring": "^7.17.7", "@babel/plugin-transform-dotall-regex": "^7.16.7", "@babel/plugin-transform-duplicate-keys": "^7.16.7", "@babel/plugin-transform-exponentiation-operator": "^7.16.7", @@ -1641,15 +1631,15 @@ "@babel/plugin-transform-literals": "^7.16.7", "@babel/plugin-transform-member-expression-literals": "^7.16.7", "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", + "@babel/plugin-transform-modules-commonjs": "^7.17.9", + "@babel/plugin-transform-modules-systemjs": "^7.17.8", "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.17.10", "@babel/plugin-transform-new-target": "^7.16.7", "@babel/plugin-transform-object-super": "^7.16.7", "@babel/plugin-transform-parameters": "^7.16.7", "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", + "@babel/plugin-transform-regenerator": "^7.17.9", "@babel/plugin-transform-reserved-words": "^7.16.7", "@babel/plugin-transform-shorthand-properties": "^7.16.7", "@babel/plugin-transform-spread": "^7.16.7", @@ -1659,11 +1649,11 @@ "@babel/plugin-transform-unicode-escapes": "^7.16.7", "@babel/plugin-transform-unicode-regex": "^7.16.7", "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", + "@babel/types": "^7.17.10", "babel-plugin-polyfill-corejs2": "^0.3.0", "babel-plugin-polyfill-corejs3": "^0.5.0", "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", + "core-js-compat": "^3.22.1", "semver": "^6.3.0" }, "engines": { @@ -1724,9 +1714,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", - "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", + "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", "dependencies": { "regenerator-runtime": "^0.13.4" }, @@ -1735,9 +1725,9 @@ } }, "node_modules/@babel/runtime-corejs3": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz", - "integrity": "sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.9.tgz", + "integrity": "sha512-WxYHHUWF2uZ7Hp1K+D1xQgbgkGUfA+5UPOegEXGt2Y5SMog/rYCVaifLZDbw8UkNXozEqqrZTy6bglL7xTaCOw==", "dependencies": { "core-js-pure": "^3.20.2", "regenerator-runtime": "^0.13.4" @@ -1760,18 +1750,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", - "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.10.tgz", + "integrity": "sha512-VmbrTHQteIdUUQNTb+zE12SHS/xQVIShmBPhlNP12hD5poF2pbITW1Z4172d03HegaQWhLffdkRJYtAzp0AGcw==", "dependencies": { "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", + "@babel/generator": "^7.17.10", "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", "@babel/helper-hoist-variables": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.3", - "@babel/types": "^7.17.0", + "@babel/parser": "^7.17.10", + "@babel/types": "^7.17.10", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1780,9 +1770,9 @@ } }, "node_modules/@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.10.tgz", + "integrity": "sha512-9O26jG0mBYfGkUYCYZRnBwbVLd1UZOICEr2Em6InB6jVfsAv1GKgwXHmrSg+WFWDmeKTA6vyTZiN8tCSM5Oo3A==", "dependencies": { "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" @@ -1849,9 +1839,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", "dependencies": { "type-fest": "^0.20.2" }, @@ -1874,20 +1864,20 @@ } }, "node_modules/@ethereumjs/common": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.6.2.tgz", - "integrity": "sha512-vDwye5v0SVeuDky4MtKsu+ogkH2oFUV8pBKzH/eNBzT8oI91pKa8WyzDuYuxOQsgNgv5R34LfFDh2aaw3H4HbQ==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.6.4.tgz", + "integrity": "sha512-RDJh/R/EAr+B7ZRg5LfJ0BIpf/1LydFgYdvZEuTraojCbVypO2sQ+QnpP5u2wJf9DASyooKqu8O4FJEWUV6NXw==", "dependencies": { "crc-32": "^1.2.0", "ethereumjs-util": "^7.1.4" } }, "node_modules/@ethereumjs/tx": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.5.0.tgz", - "integrity": "sha512-/+ZNbnJhQhXC83Xuvy6I9k4jT5sXiV0tMR9C+AzSSpcCV64+NB8dTE1m3x98RYMqb8+TLYWA+HML4F5lfXTlJw==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.5.1.tgz", + "integrity": "sha512-xzDrTiu4sqZXUcaBxJ4n4W5FrppwxLxZB4ZDGVLtxSQR4lVuOnFR6RcUHdg1mpUhAPVrmnzLJpxaeXnPxIyhWA==", "dependencies": { - "@ethereumjs/common": "^2.6.1", + "@ethereumjs/common": "^2.6.3", "ethereumjs-util": "^7.1.4" } }, @@ -1908,9 +1898,9 @@ } }, "node_modules/@ethersproject/abstract-provider": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.5.1.tgz", - "integrity": "sha512-m+MA/ful6eKbxpr99xUYeRvLkfnlqzrF8SZ46d/xFB1A7ZVknYc/sXJG0RcufF52Qn2jeFj1hhcoQ7IXjNKUqg==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.6.0.tgz", + "integrity": "sha512-oPMFlKLN+g+y7a79cLK3WiLcjWFnZQtXWgnLAbHZcN3s7L4v90UHpTOrLk+m3yr0gt+/h9STTM6zrr7PM8uoRw==", "funding": [ { "type": "individual", @@ -1922,19 +1912,19 @@ } ], "dependencies": { - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/networks": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "@ethersproject/transactions": "^5.5.0", - "@ethersproject/web": "^5.5.0" + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/networks": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/transactions": "^5.6.0", + "@ethersproject/web": "^5.6.0" } }, "node_modules/@ethersproject/abstract-signer": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.5.0.tgz", - "integrity": "sha512-lj//7r250MXVLKI7sVarXAbZXbv9P50lgmJQGr2/is82EwEb8r7HrxsmMqAjTsztMYy7ohrIhGMIml+Gx4D3mA==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.6.0.tgz", + "integrity": "sha512-WOqnG0NJKtI8n0wWZPReHtaLkDByPL67tn4nBaDAhmVq8sjHTPbCdz4DRhVu/cfTOvfy9w3iq5QZ7BX7zw56BQ==", "funding": [ { "type": "individual", @@ -1946,17 +1936,17 @@ } ], "dependencies": { - "@ethersproject/abstract-provider": "^5.5.0", - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/properties": "^5.5.0" + "@ethersproject/abstract-provider": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0" } }, "node_modules/@ethersproject/address": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.5.0.tgz", - "integrity": "sha512-l4Nj0eWlTUh6ro5IbPTgbpT4wRbdH5l8CQf7icF7sb/SI3Nhd9Y9HzhonTSTi6CefI0necIw7LJqQPopPLZyWw==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.6.0.tgz", + "integrity": "sha512-6nvhYXjbXsHPS+30sHZ+U4VMagFC/9zAk6Gd/h3S21YW4+yfb0WfRtaAIZ4kfM4rrVwqiy284LP0GtL5HXGLxQ==", "funding": [ { "type": "individual", @@ -1968,17 +1958,17 @@ } ], "dependencies": { - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/keccak256": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/rlp": "^5.5.0" + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/rlp": "^5.6.0" } }, "node_modules/@ethersproject/base64": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.5.0.tgz", - "integrity": "sha512-tdayUKhU1ljrlHzEWbStXazDpsx4eg1dBXUSI6+mHlYklOXoXF6lZvw8tnD6oVaWfnMxAgRSKROg3cVKtCcppA==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.6.0.tgz", + "integrity": "sha512-2Neq8wxJ9xHxCF9TUgmKeSh9BXJ6OAxWfeGWvbauPh8FuHEjamgHilllx8KkSd5ErxyHIX7Xv3Fkcud2kY9ezw==", "funding": [ { "type": "individual", @@ -1990,13 +1980,13 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.5.0" + "@ethersproject/bytes": "^5.6.0" } }, "node_modules/@ethersproject/bignumber": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.5.0.tgz", - "integrity": "sha512-6Xytlwvy6Rn3U3gKEc1vP7nR92frHkv6wtVr95LFR3jREXiCPzdWxKQ1cx4JGQBXxcguAwjA8murlYN2TSiEbg==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.6.0.tgz", + "integrity": "sha512-VziMaXIUHQlHJmkv1dlcd6GY2PmT0khtAqaMctCIDogxkrarMzA9L94KN1NeXqqOfFD6r0sJT3vCTOFSmZ07DA==", "funding": [ { "type": "individual", @@ -2008,15 +1998,15 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", "bn.js": "^4.11.9" } }, "node_modules/@ethersproject/bytes": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.5.0.tgz", - "integrity": "sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.6.1.tgz", + "integrity": "sha512-NwQt7cKn5+ZE4uDn+X5RAXLp46E1chXoaMmrxAyA0rblpxz8t58lVkrHXoRIn0lz1joQElQ8410GqhTqMOwc6g==", "funding": [ { "type": "individual", @@ -2028,13 +2018,13 @@ } ], "dependencies": { - "@ethersproject/logger": "^5.5.0" + "@ethersproject/logger": "^5.6.0" } }, "node_modules/@ethersproject/constants": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.5.0.tgz", - "integrity": "sha512-2MsRRVChkvMWR+GyMGY4N1sAX9Mt3J9KykCsgUFd/1mwS0UH1qw+Bv9k1UJb3X3YJYFco9H20pjSlOIfCG5HYQ==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.6.0.tgz", + "integrity": "sha512-SrdaJx2bK0WQl23nSpV/b1aq293Lh0sUaZT/yYKPDKn4tlAbkH96SPJwIhwSwTsoQQZxuh1jnqsKwyymoiBdWA==", "funding": [ { "type": "individual", @@ -2046,13 +2036,13 @@ } ], "dependencies": { - "@ethersproject/bignumber": "^5.5.0" + "@ethersproject/bignumber": "^5.6.0" } }, "node_modules/@ethersproject/hash": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.5.0.tgz", - "integrity": "sha512-dnGVpK1WtBjmnp3mUT0PlU2MpapnwWI0PibldQEq1408tQBAbZpPidkWoVVuNMOl/lISO3+4hXZWCL3YV7qzfg==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.6.0.tgz", + "integrity": "sha512-fFd+k9gtczqlr0/BruWLAu7UAOas1uRRJvOR84uDf4lNZ+bTkGl366qvniUZHKtlqxBRU65MkOobkmvmpHU+jA==", "funding": [ { "type": "individual", @@ -2064,20 +2054,20 @@ } ], "dependencies": { - "@ethersproject/abstract-signer": "^5.5.0", - "@ethersproject/address": "^5.5.0", - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/keccak256": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "@ethersproject/strings": "^5.5.0" + "@ethersproject/abstract-signer": "^5.6.0", + "@ethersproject/address": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/strings": "^5.6.0" } }, "node_modules/@ethersproject/keccak256": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.5.0.tgz", - "integrity": "sha512-5VoFCTjo2rYbBe1l2f4mccaRFN/4VQEYFwwn04aJV2h7qf4ZvI2wFxUE1XOX+snbwCLRzIeikOqtAoPwMza9kg==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.6.0.tgz", + "integrity": "sha512-tk56BJ96mdj/ksi7HWZVWGjCq0WVl/QvfhFQNeL8fxhBlGoP+L80uDCiQcpJPd+2XxkivS3lwRm3E0CXTfol0w==", "funding": [ { "type": "individual", @@ -2089,14 +2079,14 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.5.0", + "@ethersproject/bytes": "^5.6.0", "js-sha3": "0.8.0" } }, "node_modules/@ethersproject/logger": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.5.0.tgz", - "integrity": "sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.6.0.tgz", + "integrity": "sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg==", "funding": [ { "type": "individual", @@ -2109,9 +2099,9 @@ ] }, "node_modules/@ethersproject/networks": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.5.2.tgz", - "integrity": "sha512-NEqPxbGBfy6O3x4ZTISb90SjEDkWYDUbEeIFhJly0F7sZjoQMnj5KYzMSkMkLKZ+1fGpx00EDpHQCy6PrDupkQ==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.6.2.tgz", + "integrity": "sha512-9uEzaJY7j5wpYGTojGp8U89mSsgQLc40PCMJLMCnFXTs7nhBveZ0t7dbqWUNrepWTszDbFkYD6WlL8DKx5huHA==", "funding": [ { "type": "individual", @@ -2123,13 +2113,13 @@ } ], "dependencies": { - "@ethersproject/logger": "^5.5.0" + "@ethersproject/logger": "^5.6.0" } }, "node_modules/@ethersproject/properties": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.5.0.tgz", - "integrity": "sha512-l3zRQg3JkD8EL3CPjNK5g7kMx4qSwiR60/uk5IVjd3oq1MZR5qUg40CNOoEJoX5wc3DyY5bt9EbMk86C7x0DNA==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.6.0.tgz", + "integrity": "sha512-szoOkHskajKePTJSZ46uHUWWkbv7TzP2ypdEK6jGMqJaEt2sb0jCgfBo0gH0m2HBpRixMuJ6TBRaQCF7a9DoCg==", "funding": [ { "type": "individual", @@ -2141,13 +2131,13 @@ } ], "dependencies": { - "@ethersproject/logger": "^5.5.0" + "@ethersproject/logger": "^5.6.0" } }, "node_modules/@ethersproject/rlp": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.5.0.tgz", - "integrity": "sha512-hLv8XaQ8PTI9g2RHoQGf/WSxBfTB/NudRacbzdxmst5VHAqd1sMibWG7SENzT5Dj3yZ3kJYx+WiRYEcQTAkcYA==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.6.0.tgz", + "integrity": "sha512-dz9WR1xpcTL+9DtOT/aDO+YyxSSdO8YIS0jyZwHHSlAmnxA6cKU3TrTd4Xc/bHayctxTgGLYNuVVoiXE4tTq1g==", "funding": [ { "type": "individual", @@ -2159,14 +2149,14 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0" + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0" } }, "node_modules/@ethersproject/signing-key": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.5.0.tgz", - "integrity": "sha512-5VmseH7qjtNmDdZBswavhotYbWB0bOwKIlOTSlX14rKn5c11QmJwGt4GHeo7NrL/Ycl7uo9AHvEqs5xZgFBTng==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.6.1.tgz", + "integrity": "sha512-XvqQ20DH0D+bS3qlrrgh+axRMth5kD1xuvqUQUTeezxUTXBOeR6hWz2/C6FBEu39FRytyybIWrYf7YLSAKr1LQ==", "funding": [ { "type": "individual", @@ -2178,18 +2168,18 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/properties": "^5.5.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", "bn.js": "^4.11.9", "elliptic": "6.5.4", "hash.js": "1.1.7" } }, "node_modules/@ethersproject/strings": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.5.0.tgz", - "integrity": "sha512-9fy3TtF5LrX/wTrBaT8FGE6TDJyVjOvXynXJz5MT5azq+E6D92zuKNx7i29sWW2FjVOaWjAsiZ1ZWznuduTIIQ==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.6.0.tgz", + "integrity": "sha512-uv10vTtLTZqrJuqBZR862ZQjTIa724wGPWQqZrofaPI/kUsf53TBG0I0D+hQ1qyNtllbNzaW+PDPHHUI6/65Mg==", "funding": [ { "type": "individual", @@ -2201,15 +2191,15 @@ } ], "dependencies": { - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/constants": "^5.5.0", - "@ethersproject/logger": "^5.5.0" + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/constants": "^5.6.0", + "@ethersproject/logger": "^5.6.0" } }, "node_modules/@ethersproject/transactions": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.5.0.tgz", - "integrity": "sha512-9RZYSKX26KfzEd/1eqvv8pLauCKzDTub0Ko4LfIgaERvRuwyaNV78mJs7cpIgZaDl6RJui4o49lHwwCM0526zA==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.6.0.tgz", + "integrity": "sha512-4HX+VOhNjXHZyGzER6E/LVI2i6lf9ejYeWD6l4g50AdmimyuStKc39kvKf1bXWQMg7QNVh+uC7dYwtaZ02IXeg==", "funding": [ { "type": "individual", @@ -2221,21 +2211,21 @@ } ], "dependencies": { - "@ethersproject/address": "^5.5.0", - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/constants": "^5.5.0", - "@ethersproject/keccak256": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "@ethersproject/rlp": "^5.5.0", - "@ethersproject/signing-key": "^5.5.0" + "@ethersproject/address": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/constants": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/rlp": "^5.6.0", + "@ethersproject/signing-key": "^5.6.0" } }, "node_modules/@ethersproject/web": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.5.1.tgz", - "integrity": "sha512-olvLvc1CB12sREc1ROPSHTdFCdvMh0J5GSJYiQg2D0hdD4QmJDy8QYDb1CvoqD/bF1c++aeKv2sR5uduuG9dQg==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.6.0.tgz", + "integrity": "sha512-G/XHj0hV1FxI2teHRfCGvfBUHFmU+YOSbCxlAMqJklxSa7QMiHFQfAxvwY2PFqgvdkxEKwRNr/eCjfAPEm2Ctg==", "funding": [ { "type": "individual", @@ -2247,11 +2237,11 @@ } ], "dependencies": { - "@ethersproject/base64": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "@ethersproject/strings": "^5.5.0" + "@ethersproject/base64": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/strings": "^5.6.0" } }, "node_modules/@gar/promisify": { @@ -3042,37 +3032,57 @@ "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==", + "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.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.6.tgz", + "integrity": "sha512-R7xHtBSNm+9SyvpJkdQl+qrM3Hm2fea3Ef197M3mUug+v+yR+Rhfbs7PBtcBUVnIWJ4JcAdjvij+c8hXS9p5aw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.0.tgz", + "integrity": "sha512-SfJxIxNVYLTsKwzB3MoOQ1yxf4w/E6MdkvTgrgAt1bfxjSrLUoHMKrDOykwN14q65waezZIdqDneUIPh4/sKxg==", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==" + "version": "1.4.12", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.12.tgz", + "integrity": "sha512-az/NhpIwP3K33ILr0T2bso+k2E/SLf8Yidd8mHl0n6sCQ4YdyC8qDhZA6kOPDNDBA56ZnIjngVl0U3jREA0BUA==" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "node_modules/@mapbox/node-pre-gyp": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz", - "integrity": "sha512-CMGKi28CF+qlbXh26hDe6NxCd7amqeAzEqnS6IHeO6LoaKyM/n+Xw3HT1COdq8cuioOdlKdqn/hCmqPUOMOywg==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz", + "integrity": "sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==", "dependencies": { - "detect-libc": "^1.0.3", + "detect-libc": "^2.0.0", "https-proxy-agent": "^5.0.0", "make-dir": "^3.1.0", - "node-fetch": "^2.6.5", + "node-fetch": "^2.6.7", "nopt": "^5.0.0", "npmlog": "^5.0.1", "rimraf": "^3.0.2", @@ -3084,9 +3094,9 @@ } }, "node_modules/@mapbox/node-pre-gyp/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -3098,16 +3108,15 @@ } }, "node_modules/@material-ui/core": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.3.tgz", - "integrity": "sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw==", - "deprecated": "You can now upgrade to @mui/material. See the guide: https://mui.com/guides/migration-v4/", + "version": "4.12.4", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.4.tgz", + "integrity": "sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ==", "dependencies": { "@babel/runtime": "^7.4.4", - "@material-ui/styles": "^4.11.4", - "@material-ui/system": "^4.12.1", + "@material-ui/styles": "^4.11.5", + "@material-ui/system": "^4.12.2", "@material-ui/types": "5.1.0", - "@material-ui/utils": "^4.11.2", + "@material-ui/utils": "^4.11.3", "@types/react-transition-group": "^4.2.0", "clsx": "^1.0.4", "hoist-non-react-statics": "^3.3.2", @@ -3134,37 +3143,18 @@ } } }, - "node_modules/@material-ui/core/node_modules/@material-ui/styles": { - "version": "4.11.4", - "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.4.tgz", - "integrity": "sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew==", - "deprecated": "You can now upgrade to @mui/styles. See the guide: https://mui.com/guides/migration-v4/", + "node_modules/@material-ui/icons": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.3.tgz", + "integrity": "sha512-IKHlyx6LDh8n19vzwH5RtHIOHl9Tu90aAAxcbWME6kp4dmvODM3UvOHJeMIDzUbd4muuJKHmlNoBN+mDY4XkBA==", "dependencies": { - "@babel/runtime": "^7.4.4", - "@emotion/hash": "^0.8.0", - "@material-ui/types": "5.1.0", - "@material-ui/utils": "^4.11.2", - "clsx": "^1.0.4", - "csstype": "^2.5.2", - "hoist-non-react-statics": "^3.3.2", - "jss": "^10.5.1", - "jss-plugin-camel-case": "^10.5.1", - "jss-plugin-default-unit": "^10.5.1", - "jss-plugin-global": "^10.5.1", - "jss-plugin-nested": "^10.5.1", - "jss-plugin-props-sort": "^10.5.1", - "jss-plugin-rule-value-function": "^10.5.1", - "jss-plugin-vendor-prefixer": "^10.5.1", - "prop-types": "^15.7.2" + "@babel/runtime": "^7.4.4" }, "engines": { "node": ">=8.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/material-ui" - }, "peerDependencies": { + "@material-ui/core": "^4.0.0", "@types/react": "^16.8.6 || ^17.0.0", "react": "^16.8.0 || ^17.0.0", "react-dom": "^16.8.0 || ^17.0.0" @@ -3175,25 +3165,22 @@ } } }, - "node_modules/@material-ui/core/node_modules/@material-ui/system": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.1.tgz", - "integrity": "sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==", - "deprecated": "You can now upgrade to @mui/system. See the guide: https://mui.com/guides/migration-v4/", + "node_modules/@material-ui/lab": { + "version": "4.0.0-alpha.61", + "resolved": "https://registry.npmjs.org/@material-ui/lab/-/lab-4.0.0-alpha.61.tgz", + "integrity": "sha512-rSzm+XKiNUjKegj8bzt5+pygZeckNLOr+IjykH8sYdVk7dE9y2ZuUSofiMV2bJk3qU+JHwexmw+q0RyNZB9ugg==", "dependencies": { "@babel/runtime": "^7.4.4", - "@material-ui/utils": "^4.11.2", - "csstype": "^2.5.2", - "prop-types": "^15.7.2" + "@material-ui/utils": "^4.11.3", + "clsx": "^1.0.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0" }, "engines": { "node": ">=8.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/material-ui" - }, "peerDependencies": { + "@material-ui/core": "^4.12.1", "@types/react": "^16.8.6 || ^17.0.0", "react": "^16.8.0 || ^17.0.0", "react-dom": "^16.8.0 || ^17.0.0" @@ -3204,56 +3191,64 @@ } } }, - "node_modules/@material-ui/core/node_modules/@material-ui/utils": { - "version": "4.11.2", - "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz", - "integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==", + "node_modules/@material-ui/styles": { + "version": "4.11.5", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.5.tgz", + "integrity": "sha512-o/41ot5JJiUsIETME9wVLAJrmIWL3j0R0Bj2kCOLbSfqEkKf0fmaPt+5vtblUh5eXr2S+J/8J3DaCb10+CzPGA==", "dependencies": { "@babel/runtime": "^7.4.4", - "prop-types": "^15.7.2", - "react-is": "^16.8.0 || ^17.0.0" + "@emotion/hash": "^0.8.0", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.3", + "clsx": "^1.0.4", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.5.1", + "jss-plugin-camel-case": "^10.5.1", + "jss-plugin-default-unit": "^10.5.1", + "jss-plugin-global": "^10.5.1", + "jss-plugin-nested": "^10.5.1", + "jss-plugin-props-sort": "^10.5.1", + "jss-plugin-rule-value-function": "^10.5.1", + "jss-plugin-vendor-prefixer": "^10.5.1", + "prop-types": "^15.7.2" }, "engines": { "node": ">=8.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", "react": "^16.8.0 || ^17.0.0", "react-dom": "^16.8.0 || ^17.0.0" - } - }, - "node_modules/@material-ui/core/node_modules/csstype": { - "version": "2.6.19", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.19.tgz", - "integrity": "sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==" - }, - "node_modules/@material-ui/core/node_modules/react-transition-group": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", - "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", - "dependencies": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" }, - "peerDependencies": { - "react": ">=16.6.0", - "react-dom": ">=16.6.0" + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@material-ui/icons": { - "version": "4.11.2", - "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.2.tgz", - "integrity": "sha512-fQNsKX2TxBmqIGJCSi3tGTO/gZ+eJgWmMJkgDiOfyNaunNaxcklJQFaFogYcFl0qFuaEz1qaXYXboa/bUXVSOQ==", - "deprecated": "You can now upgrade to @mui/icons. See the guide: https://mui.com/guides/migration-v4/", + "node_modules/@material-ui/system": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.2.tgz", + "integrity": "sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw==", "dependencies": { - "@babel/runtime": "^7.4.4" + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.11.3", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" }, "engines": { "node": ">=8.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, "peerDependencies": { - "@material-ui/core": "^4.0.0", "@types/react": "^16.8.6 || ^17.0.0", "react": "^16.8.0 || ^17.0.0", "react-dom": "^16.8.0 || ^17.0.0" @@ -3264,26 +3259,12 @@ } } }, - "node_modules/@material-ui/lab": { - "version": "4.0.0-alpha.60", - "resolved": "https://registry.npmjs.org/@material-ui/lab/-/lab-4.0.0-alpha.60.tgz", - "integrity": "sha512-fadlYsPJF+0fx2lRuyqAuJj7hAS1tLDdIEEdov5jlrpb5pp4b+mRDUqQTUxi4inRZHS1bEXpU8QWUhO6xX88aA==", - "deprecated": "You can now upgrade to @mui/lab. See the guide: https://mui.com/guides/migration-v4/", - "dependencies": { - "@babel/runtime": "^7.4.4", - "@material-ui/utils": "^4.11.2", - "clsx": "^1.0.4", - "prop-types": "^15.7.2", - "react-is": "^16.8.0 || ^17.0.0" - }, - "engines": { - "node": ">=8.0.0" - }, + "node_modules/@material-ui/types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==", "peerDependencies": { - "@material-ui/core": "^4.12.1", - "@types/react": "^16.8.6 || ^17.0.0", - "react": "^16.8.0 || ^17.0.0", - "react-dom": "^16.8.0 || ^17.0.0" + "@types/react": "*" }, "peerDependenciesMeta": { "@types/react": { @@ -3291,10 +3272,10 @@ } } }, - "node_modules/@material-ui/lab/node_modules/@material-ui/utils": { - "version": "4.11.2", - "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz", - "integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==", + "node_modules/@material-ui/utils": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.3.tgz", + "integrity": "sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==", "dependencies": { "@babel/runtime": "^7.4.4", "prop-types": "^15.7.2", @@ -3308,19 +3289,6 @@ "react-dom": "^16.8.0 || ^17.0.0" } }, - "node_modules/@material-ui/types": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", - "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==", - "peerDependencies": { - "@types/react": "*" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -3363,9 +3331,9 @@ } }, "node_modules/@npmcli/fs/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -3445,14 +3413,6 @@ } } }, - "node_modules/@pmmmwh/react-refresh-webpack-plugin/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==", - "engines": { - "node": ">= 8" - } - }, "node_modules/@rollup/plugin-node-resolve": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz", @@ -3550,15 +3510,15 @@ } }, "node_modules/@slack/web-api": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@slack/web-api/-/web-api-6.7.0.tgz", - "integrity": "sha512-Jd0ZC/aolkdeM2m3j0SYASlzoUe1AWgm19eDkmGjfli6CzoW1benYHqgMh1owS7+gLfe4FEILtE0fyVDZjgmGQ==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/@slack/web-api/-/web-api-6.7.1.tgz", + "integrity": "sha512-Aa2E/7NtGagd7mVsFCrc69iZMoviR2032SBOic06sYVvptdzJlvNsSQVqLCb1Aqz7r/jodb2fnXO1gl016OcWQ==", "dependencies": { "@slack/logger": "^3.0.0", "@slack/types": "^2.0.0", "@types/is-stream": "^1.1.0", "@types/node": ">=12.0.0", - "axios": "^0.25.0", + "axios": "^0.26.1", "eventemitter3": "^3.1.0", "form-data": "^2.5.0", "is-electron": "2.2.0", @@ -3572,11 +3532,11 @@ } }, "node_modules/@slack/web-api/node_modules/axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", "dependencies": { - "follow-redirects": "^1.14.7" + "follow-redirects": "^1.14.8" } }, "node_modules/@surma/rollup-plugin-off-main-thread": { @@ -3823,9 +3783,9 @@ } }, "node_modules/@types/babel__core": { - "version": "7.1.18", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", - "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0", @@ -3852,9 +3812,9 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", - "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", + "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", + "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", "dependencies": { "@babel/types": "^7.3.0" } @@ -3942,9 +3902,9 @@ } }, "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==" + "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==" }, "node_modules/@types/json5": { "version": "0.0.29", @@ -3957,9 +3917,9 @@ "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==" }, "node_modules/@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==" + "version": "17.0.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.31.tgz", + "integrity": "sha512-AR0x5HbXGqkEx9CadRH3EBYx/VkiUgZIhP4wvPn/+5KIsgpNoyFaRlVe0Zlx9gRtg8fA06a9tskE2MSN7TcG4Q==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -3980,14 +3940,14 @@ } }, "node_modules/@types/prettier": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.4.tgz", - "integrity": "sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA==" + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.0.tgz", + "integrity": "sha512-G/AdOadiZhnJp0jXCaBQU449W2h716OW/EoXeYkCytxKL06X1WCXB4DZpp8TpZ8eyIJVS1cw4lrlkkSYU21cDw==" }, "node_modules/@types/prop-types": { - "version": "15.7.4", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", - "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "node_modules/@types/q": { "version": "1.5.5", @@ -3995,9 +3955,9 @@ "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" }, "node_modules/@types/react": { - "version": "16.14.23", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.23.tgz", - "integrity": "sha512-WngBZLuSkP4IAgPi0HOsGCHo6dn3CcuLQnCfC17VbA7YBgipZiZoTOhObwl/93DsFW0Y2a/ZXeonpW4DxirEJg==", + "version": "16.14.25", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.25.tgz", + "integrity": "sha512-cXRVHd7vBT5v1is72mmvmsg9stZrbJO04DJqFeh3Yj2tVKO6vmxg5BI+ybI6Ls7ROXRG3aFbZj9x0WA3ZAoDQw==", "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -4005,18 +3965,18 @@ } }, "node_modules/@types/react-dom": { - "version": "16.9.14", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.14.tgz", - "integrity": "sha512-FIX2AVmPTGP30OUJ+0vadeIFJJ07Mh1m+U0rxfgyW34p3rTlXI+nlenvAxNn4BP36YyI9IJ/+UJ7Wu22N1pI7A==", + "version": "16.9.15", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.15.tgz", + "integrity": "sha512-PjWhZj54ACucQX2hDmnHyqHz+N2On5g3Lt5BeNn+wy067qvOokVSQw1nEog1XGfvLYrSl3cyrdebEfjQQNXD3A==", "peer": true, "dependencies": { "@types/react": "^16" } }, "node_modules/@types/react-redux": { - "version": "7.1.22", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.22.tgz", - "integrity": "sha512-GxIA1kM7ClU73I6wg9IRTVwSO9GS+SAKZKe0Enj+82HMU6aoESFU2HNAdNi3+J53IaOHPiUfT3kSG4L828joDQ==", + "version": "7.1.24", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.24.tgz", + "integrity": "sha512-7FkurKcS1k0FHZEtdbbgN8Oc6b+stGSfZYjQGicofJ0j4U0qIn/jaSvnP2pLwZKiai3/17xqqxkkrxTgN8UNbQ==", "dependencies": { "@types/hoist-non-react-statics": "^3.3.0", "@types/react": "*", @@ -4032,6 +3992,11 @@ "@types/react": "*" } }, + "node_modules/@types/react/node_modules/csstype": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", + "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" + }, "node_modules/@types/resolve": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz", @@ -4041,9 +4006,9 @@ } }, "node_modules/@types/retry": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", - "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==" + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" }, "node_modules/@types/scheduler": { "version": "0.16.2", @@ -4074,9 +4039,9 @@ "integrity": "sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ==" }, "node_modules/@types/uglify-js": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.1.tgz", - "integrity": "sha512-O3MmRAk6ZuAKa9CHgg0Pr0+lUOqoMLpc9AS4R8ano2auvsg7IE8syF3Xh/NPr26TWklxYcqoEEFdzLLs1fV9PQ==", + "version": "3.13.2", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.2.tgz", + "integrity": "sha512-/xFrPIo+4zOeNGtVMbf9rUm0N+i4pDf1ynExomqtokIJmVzR3962lJ1UE+MmexMkA0cmN9oTzg5Xcbwge0Ij2Q==", "dependencies": { "source-map": "^0.6.1" } @@ -4112,14 +4077,6 @@ "source-map": "^0.7.3" } }, - "node_modules/@types/webpack-sources/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==", - "engines": { - "node": ">= 8" - } - }, "node_modules/@types/webpack/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -4137,9 +4094,9 @@ } }, "node_modules/@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==" + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "4.33.0", @@ -4181,9 +4138,9 @@ } }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -4315,9 +4272,9 @@ } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -4512,9 +4469,9 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, "node_modules/abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==" + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==" }, "node_modules/abbrev": { "version": "1.1.1", @@ -4824,13 +4781,13 @@ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, "node_modules/array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", + "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", "get-intrinsic": "^1.1.1", "is-string": "^1.0.7" }, @@ -4866,26 +4823,28 @@ } }, "node_modules/array.prototype.find": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.1.2.tgz", - "integrity": "sha512-00S1O4ewO95OmmJW7EesWfQlrCrLEL8kZ40w3+GkLX2yTt0m2ggcePPa2uHPJ9KUmJvwRq+lCV9bD8Yim23x/Q==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.2.0.tgz", + "integrity": "sha512-sn40qmUiLYAcRb/1HsIQjTTZ1kCy8II8VtZJpMn2Aoen9twULhbWXisfh3HimGqMlHGUul0/TfKCnXg42LuPpQ==", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "es-abstract": "^1.19.4", + "es-shim-unscopables": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -4895,13 +4854,14 @@ } }, "node_modules/array.prototype.flatmap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz", - "integrity": "sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz", + "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==", "dependencies": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" }, "engines": { "node": ">= 0.4" @@ -4994,9 +4954,9 @@ } }, "node_modules/async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "dependencies": { "lodash": "^4.17.14" } @@ -5620,9 +5580,9 @@ } }, "node_modules/blakejs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.1.1.tgz", - "integrity": "sha512-bLG6PHOCZJKNshTjGRBvET0vTciwQE6zFKOKKXPDJfwFBd4Ac0yBfPZqcGvGJap50l7ktvlpFqc2jGVaUgbJgg==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" }, "node_modules/bluebird": { "version": "3.7.2", @@ -5635,23 +5595,26 @@ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, "node_modules/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.7", - "raw-body": "2.4.3", - "type-is": "~1.6.18" + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, "node_modules/body-parser/node_modules/debug": { @@ -5830,14 +5793,24 @@ } }, "node_modules/browserslist": { - "version": "4.19.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.3.tgz", - "integrity": "sha512-XK3X4xtKJ+Txj8G5c30B4gsm71s69lqXlkYui4s6EkKxuv49qjYlY6oVd+IFJ73d4YymtM3+djvvt/R/iJwwDg==", + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], "dependencies": { - "caniuse-lite": "^1.0.30001312", - "electron-to-chromium": "^1.4.71", + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", "escalade": "^3.1.1", - "node-releases": "^2.0.2", + "node-releases": "^2.0.3", "picocolors": "^1.0.0" }, "bin": { @@ -5845,10 +5818,6 @@ }, "engines": { "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" } }, "node_modules/bs58": { @@ -6120,9 +6089,9 @@ } }, "node_modules/camel-case/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, "node_modules/camelcase": { "version": "6.3.0", @@ -6147,13 +6116,19 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001312", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz", - "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } + "version": "1.0.30001335", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001335.tgz", + "integrity": "sha512-ddP1Tgm7z2iIxu6QTtbZUv6HJxSaV/PZeSrWFZtbY4JZ69tOeNhBCl3HyRQgeNZKE5AOn1kpV7fhljigy0Ty3w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] }, "node_modules/capture-exit": { "version": "2.0.0", @@ -6517,9 +6492,9 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "node_modules/color-string": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz", - "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" @@ -6806,9 +6781,9 @@ } }, "node_modules/core-js": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz", - "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==", + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.22.4.tgz", + "integrity": "sha512-1uLykR+iOfYja+6Jn/57743gc9n73EWiOnSJJ4ba3B4fOEYDBv25MagmEZBxTp5cWq4b/KPx/l77zgsp28ju4w==", "hasInstallScript": true, "funding": { "type": "opencollective", @@ -6816,11 +6791,11 @@ } }, "node_modules/core-js-compat": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.1.tgz", - "integrity": "sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g==", + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.4.tgz", + "integrity": "sha512-dIWcsszDezkFZrfm1cnB4f/J85gyhiCpxbgBdohWCDtSVuAaChTSpPV7ldOQf/Xds2U5xCIJZOK82G4ZPAIswA==", "dependencies": { - "browserslist": "^4.19.1", + "browserslist": "^4.20.3", "semver": "7.0.0" }, "funding": { @@ -6837,9 +6812,9 @@ } }, "node_modules/core-js-pure": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.1.tgz", - "integrity": "sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==", + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.22.4.tgz", + "integrity": "sha512-4iF+QZkpzIz0prAFuepmxwJ2h5t4agvE8WPYqs2mjLJMNNwJOnpch76w2Q7bUfCPEv/V7wpvOfog0w273M+ZSw==", "hasInstallScript": true, "funding": { "type": "opencollective", @@ -6879,13 +6854,9 @@ } }, "node_modules/crc-32": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.1.tgz", - "integrity": "sha512-Dn/xm/1vFFgs3nfrpEVScHoIslO9NZRITWGz/1E/St6u4xw99vfZzVkW0OSnzx2h9egej9xwMCEut6sqwokM/w==", - "dependencies": { - "exit-on-epipe": "~1.0.1", - "printj": "~1.3.1" - }, + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", "bin": { "crc32": "bin/crc32.njs" }, @@ -7083,9 +7054,9 @@ } }, "node_modules/css-loader/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -7111,13 +7082,13 @@ } }, "node_modules/css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "dependencies": { "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", "domutils": "^2.8.0", "nth-check": "^2.0.1" }, @@ -7160,9 +7131,9 @@ } }, "node_modules/css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "engines": { "node": ">= 6" }, @@ -7387,9 +7358,9 @@ "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==" }, "node_modules/csstype": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", - "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" }, "node_modules/cyclist": { "version": "1.0.1", @@ -7459,14 +7430,14 @@ } }, "node_modules/dayjs": { - "version": "1.10.7", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz", - "integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==" + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.1.tgz", + "integrity": "sha512-ER7EjqVAMkRRsxNCC5YqJ9d9VQYuWdGt7aiH2qA5R5wt8ZmWaP2dLUSIK6y/kVzLMlmh1Tvu5xUf4M/wdGJ5KA==" }, "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { "ms": "2.1.2" }, @@ -7663,14 +7634,18 @@ "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" }, "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", "dependencies": { - "object-keys": "^1.0.12" + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/define-property": { @@ -7777,11 +7752,11 @@ } }, "node_modules/depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/des.js": { @@ -7794,19 +7769,20 @@ } }, "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } }, "node_modules/detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", - "bin": { - "detect-libc": "bin/detect-libc.js" - }, + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", "engines": { - "node": ">=0.10" + "node": ">=8" } }, "node_modules/detect-newline": { @@ -7930,10 +7906,15 @@ "csstype": "^3.0.2" } }, + "node_modules/dom-helpers/node_modules/csstype": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", + "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" + }, "node_modules/dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "dependencies": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", @@ -7958,9 +7939,9 @@ } }, "node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "funding": [ { "type": "github", @@ -7988,9 +7969,9 @@ } }, "node_modules/domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "dependencies": { "domelementtype": "^2.2.0" }, @@ -8024,9 +8005,9 @@ } }, "node_modules/dot-case/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, "node_modules/dot-prop": { "version": "5.3.0", @@ -8113,9 +8094,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.72", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.72.tgz", - "integrity": "sha512-9LkRQwjW6/wnSfevR21a3k8sOJ+XWSH7kkzs9/EUenKmuDkndP3W9y1yCZpOxufwGbX3JV8glZZSDb4o95zwXQ==" + "version": "1.4.132", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.132.tgz", + "integrity": "sha512-JYdZUw/1068NWN+SwXQ7w6Ue0bWYGihvSUNNQwurvcDV/SM7vSiGZ3NuFvFgoEiCs4kB8xs3cX2an3wB7d4TBw==" }, "node_modules/elliptic": { "version": "6.5.4", @@ -8243,9 +8224,9 @@ } }, "node_modules/es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.5.tgz", + "integrity": "sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA==", "dependencies": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", @@ -8253,15 +8234,15 @@ "get-intrinsic": "^1.1.1", "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.2", + "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", + "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", + "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", "string.prototype.trimend": "^1.0.4", @@ -8275,6 +8256,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dependencies": { + "has": "^1.0.3" + } + }, "node_modules/es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -8292,13 +8281,17 @@ } }, "node_modules/es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "version": "0.10.61", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.61.tgz", + "integrity": "sha512-yFhIqQAzu2Ca2I4SE2Au3rxVfmohU9Y7wqGR+s7+H7krk26NXhIRAZDgqd6xqjCEFUomDEA3/Bo/7fKmIkW1kA==", + "hasInstallScript": true, "dependencies": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" } }, "node_modules/es6-iterator": { @@ -8598,23 +8591,23 @@ } }, "node_modules/eslint-plugin-import": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", - "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "dependencies": { "array-includes": "^3.1.4", "array.prototype.flat": "^1.2.5", "debug": "^2.6.9", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.2", + "eslint-module-utils": "^2.7.3", "has": "^1.0.3", - "is-core-module": "^2.8.0", + "is-core-module": "^2.8.1", "is-glob": "^4.0.3", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.12.0" + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" }, "engines": { "node": ">=4" @@ -8693,21 +8686,21 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz", - "integrity": "sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==", + "version": "7.29.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.29.4.tgz", + "integrity": "sha512-CVCXajliVh509PcZYRFyu/BoUEz452+jtQJq2b3Bae4v3xBUWPLCmtmBM+ZinG4MzwmxJgJ2M5rMqhqLVn7MtQ==", "dependencies": { "array-includes": "^3.1.4", "array.prototype.flatmap": "^1.2.5", "doctrine": "^2.1.0", "estraverse": "^5.3.0", "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "object.entries": "^1.1.5", "object.fromentries": "^2.0.5", "object.hasown": "^1.1.0", "object.values": "^1.1.5", - "prop-types": "^15.7.2", + "prop-types": "^15.8.1", "resolve": "^2.0.0-next.3", "semver": "^6.3.0", "string.prototype.matchall": "^4.0.6" @@ -8720,9 +8713,9 @@ } }, "node_modules/eslint-plugin-react-hooks": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz", - "integrity": "sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.5.0.tgz", + "integrity": "sha512-8k1gRt7D7h03kd+SAAlzXkQwWK22BnK6GKZG+FJA6BAGy22CFvl8kCIXKpVux0cCxMWDQUPqSok0LKaZ0aOcCw==", "engines": { "node": ">=10" }, @@ -8853,9 +8846,9 @@ } }, "node_modules/eslint-plugin-testing-library/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -9022,9 +9015,9 @@ } }, "node_modules/eslint/node_modules/globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", "dependencies": { "type-fest": "^0.20.2" }, @@ -9044,9 +9037,9 @@ } }, "node_modules/eslint/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -9355,14 +9348,6 @@ "node": ">= 0.8.0" } }, - "node_modules/exit-on-epipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", - "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==", - "engines": { - "node": ">=0.8" - } - }, "node_modules/expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", @@ -9535,37 +9520,38 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/express": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", - "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", + "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.2", + "body-parser": "1.20.0", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.2", + "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "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.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", - "qs": "6.9.7", + "qs": "6.10.3", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", + "send": "0.18.0", + "serve-static": "1.15.0", "setprototypeof": "1.2.0", - "statuses": "~1.5.0", + "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -9575,9 +9561,9 @@ } }, "node_modules/express/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==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", "engines": { "node": ">= 0.6" } @@ -9835,16 +9821,16 @@ } }, "node_modules/finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "statuses": "~1.5.0", + "statuses": "2.0.1", "unpipe": "~1.0.0" }, "engines": { @@ -9949,9 +9935,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.0.tgz", + "integrity": "sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==", "funding": [ { "type": "individual", @@ -10289,9 +10275,9 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" }, "node_modules/functions-have-names": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.2.tgz", - "integrity": "sha512-bLgc3asbWdwPbx2mNk2S49kmJCuQeu0nfmaOgbs8WIyzzkw3r4htszdIi9Q9EMezDPTYuJx2wvjZ/EwgAthpnA==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -10549,9 +10535,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, "node_modules/growly": { "version": "1.3.0", @@ -10614,9 +10600,9 @@ } }, "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -10629,6 +10615,17 @@ "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==", + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-symbol-support-x": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", @@ -10638,9 +10635,9 @@ } }, "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "engines": { "node": ">= 0.4" }, @@ -10976,18 +10973,18 @@ "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=" }, "node_modules/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dependencies": { - "depd": "~1.1.2", + "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", + "statuses": "2.0.1", "toidentifier": "1.0.1" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/http-https": { @@ -10996,9 +10993,9 @@ "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=" }, "node_modules/http-parser-js": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.5.tgz", - "integrity": "sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA==" + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz", + "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==" }, "node_modules/http-proxy": { "version": "1.18.1", @@ -11186,9 +11183,9 @@ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" }, "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "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==", "dependencies": { "agent-base": "6", "debug": "4" @@ -11650,9 +11647,9 @@ } }, "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", "dependencies": { "has": "^1.0.3" }, @@ -11829,9 +11826,9 @@ } }, "node_modules/is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "dependencies": { "has-tostringtag": "^1.0.0" }, @@ -11957,9 +11954,12 @@ } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dependencies": { + "call-bind": "^1.0.2" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -12085,9 +12085,9 @@ } }, "node_modules/istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -13536,9 +13536,9 @@ } }, "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -13993,9 +13993,9 @@ } }, "node_modules/jsdom/node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", "bin": { "acorn": "bin/acorn" }, @@ -14086,18 +14086,10 @@ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, - "node_modules/json3": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", - "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==" - }, "node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dependencies": { - "minimist": "^1.2.5" - }, + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", "bin": { "json5": "lib/cli.js" }, @@ -14241,12 +14233,17 @@ "jss": "10.9.0" } }, + "node_modules/jss/node_modules/csstype": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", + "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" + }, "node_modules/jsx-ast-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", - "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.0.tgz", + "integrity": "sha512-XzO9luP6L0xkxwhIJMTJQpZo/eeN60K08jHdexfD569AGxeNug6UketeHXEhROoM8aR7EcUoOQmIhcJQjcuq8Q==", "dependencies": { - "array-includes": "^3.1.3", + "array-includes": "^3.1.4", "object.assign": "^4.1.2" }, "engines": { @@ -14486,6 +14483,11 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" + }, "node_modules/lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -14545,9 +14547,9 @@ } }, "node_modules/lower-case/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, "node_modules/lowercase-keys": { "version": "1.0.1", @@ -14569,11 +14571,11 @@ } }, "node_modules/magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", "dependencies": { - "sourcemap-codec": "^1.4.4" + "sourcemap-codec": "^1.4.8" } }, "node_modules/make-dir": { @@ -14687,12 +14689,12 @@ "integrity": "sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==" }, "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" @@ -14722,19 +14724,19 @@ } }, "node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "engines": { "node": ">= 0.6" } }, "node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dependencies": { - "mime-db": "1.51.0" + "mime-db": "1.52.0" }, "engines": { "node": ">= 0.6" @@ -14844,9 +14846,9 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "node_modules/minipass": { "version": "3.1.6", @@ -14937,11 +14939,11 @@ } }, "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dependencies": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" @@ -15104,9 +15106,9 @@ "integrity": "sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18=" }, "node_modules/nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -15162,9 +15164,9 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "node_modules/next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" }, "node_modules/nice-try": { "version": "1.0.5", @@ -15181,9 +15183,9 @@ } }, "node_modules/no-case/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, "node_modules/node-addon-api": { "version": "3.2.1", @@ -15218,9 +15220,9 @@ } }, "node_modules/node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", + "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==", "bin": { "node-gyp-build": "bin.js", "node-gyp-build-optional": "optional.js", @@ -15305,9 +15307,9 @@ } }, "node_modules/node-notifier/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "optional": true, "dependencies": { "lru-cache": "^6.0.0" @@ -15341,14 +15343,14 @@ } }, "node_modules/node-releases": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", - "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", + "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==" }, "node_modules/nodemailer": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.2.tgz", - "integrity": "sha512-Dz7zVwlef4k5R71fdmxwR8Q39fiboGbu3xgswkzGwczUfjp873rVxt1O46+Fh0j1ORnAC6L9+heI8uUpO6DT7Q==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.5.tgz", + "integrity": "sha512-6VtMpwhsrixq1HDYSBBHvW0GwiWawE75dS3oal48VqRhUvKJNnKnJo2RI/bCVQubj1vgrgscMNW4DHaD6xtMCg==", "engines": { "node": ">=6.0.0" } @@ -18398,9 +18400,9 @@ "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" }, "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dependencies": { "ee-first": "1.1.1" }, @@ -18619,11 +18621,11 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, "node_modules/p-retry": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz", - "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "dependencies": { - "@types/retry": "^0.12.0", + "@types/retry": "0.12.0", "retry": "^0.13.1" }, "engines": { @@ -18674,9 +18676,9 @@ } }, "node_modules/param-case/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, "node_modules/parent-module": { "version": "1.0.1", @@ -18702,9 +18704,9 @@ } }, "node_modules/parse-headers": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.4.tgz", - "integrity": "sha512-psZ9iZoCNFLrgRjZ1d8mn0h9WRqJwFxM9q3x7iUjN/YT2OksthDJ5TiPCu2F38kS4zutqfW+YdVVkBZZx3/1aw==" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", + "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==" }, "node_modules/parse-json": { "version": "5.2.0", @@ -18754,9 +18756,9 @@ } }, "node_modules/pascal-case/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" }, "node_modules/pascalcase": { "version": "0.1.1", @@ -20164,20 +20166,26 @@ } }, "node_modules/postcss-safe-parser/node_modules/postcss": { - "version": "8.4.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", - "integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", + "version": "8.4.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.13.tgz", + "integrity": "sha512-jtL6eTBrza5MPzy8oJLFuUscHDXTV5KcLlqAWHl5q5WYRfnNRGSmOZmOZ1T6Gy7A99mOZfqungmZMpMmCVJ8ZA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], "dependencies": { - "nanoid": "^3.2.0", + "nanoid": "^3.3.3", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, "engines": { "node": "^10 || ^12 || >=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" } }, "node_modules/postcss-selector-matches": { @@ -20199,9 +20207,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", - "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -20352,17 +20360,6 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/printj": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/printj/-/printj-1.3.1.tgz", - "integrity": "sha512-GA3TdL8szPK4AQ2YnOe/b+Y1jUFwmmGMMK/qbY7VcE3Z7FU8JstbKiKRzO6CIiAKPhTO8m01NoQ0V5f3jc4OGg==", - "bin": { - "printj": "bin/printj.njs" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -20520,9 +20517,12 @@ } }, "node_modules/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==", + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dependencies": { + "side-channel": "^1.0.4" + }, "engines": { "node": ">=0.6" }, @@ -20621,12 +20621,12 @@ } }, "node_modules/raw-body": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", - "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "dependencies": { "bytes": "3.1.2", - "http-errors": "1.8.1", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, @@ -20869,9 +20869,9 @@ } }, "node_modules/react-error-overlay": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz", - "integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==" + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, "node_modules/react-fast-compare": { "version": "2.0.4", @@ -20884,9 +20884,9 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "node_modules/react-redux": { - "version": "7.2.6", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz", - "integrity": "sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==", + "version": "7.2.8", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.8.tgz", + "integrity": "sha512-6+uDjhs3PSIclqoCk0kd6iX74gzrGc3W5zcAjbrFgEdIjRSQObdIwfx80unTkVUYvbQ95Y8Av3OvFHq1w5EOUw==", "dependencies": { "@babel/runtime": "^7.15.4", "@types/react-redux": "^7.1.20", @@ -20896,7 +20896,7 @@ "react-is": "^17.0.2" }, "peerDependencies": { - "react": "^16.8.3 || ^17" + "react": "^16.8.3 || ^17 || ^18" }, "peerDependenciesMeta": { "react-dom": { @@ -21067,6 +21067,14 @@ "node": ">=10" } }, + "node_modules/react-scripts/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-toasts": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/react-toasts/-/react-toasts-3.0.6.tgz", @@ -21079,6 +21087,21 @@ "@types/react-dom": "^16.8.2" } }, + "node_modules/react-transition-group": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", + "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -21238,9 +21261,9 @@ } }, "node_modules/redux": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz", - "integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz", + "integrity": "sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==", "dependencies": { "@babel/runtime": "^7.9.2" } @@ -21280,9 +21303,9 @@ "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" }, "node_modules/regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", "dependencies": { "@babel/runtime": "^7.8.4" } @@ -21305,12 +21328,13 @@ "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==" }, "node_modules/regexp.prototype.flags": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", - "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" }, "engines": { "node": ">= 0.4" @@ -22325,9 +22349,9 @@ } }, "node_modules/sass-loader/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -22431,23 +22455,23 @@ } }, "node_modules/send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dependencies": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "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": "1.8.1", + "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "2.0.1" }, "engines": { "node": ">= 0.8.0" @@ -22504,6 +22528,14 @@ "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": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "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", @@ -22533,15 +22565,23 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.2" + "send": "0.18.0" }, "engines": { "node": ">= 0.8.0" @@ -22948,6 +22988,14 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "node_modules/snapdragon/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -22959,16 +23007,21 @@ } }, "node_modules/sockjs-client": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.5.2.tgz", - "integrity": "sha512-ZzRxPBISQE7RpzlH4tKJMQbHM9pabHluk0WBaxAQ+wm/UieeBVBou0p4wVnSQGN9QmpAZygQ0cDIypWuqOFmFQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.6.0.tgz", + "integrity": "sha512-qVHJlyfdHFht3eBFZdKEXKTlb7I4IV41xnVNo8yUKA1UHcPJwgW2SvTq9LhnjjCywSkSK7c/e4nghU0GOoMCRQ==", "dependencies": { - "debug": "^3.2.6", - "eventsource": "^1.0.7", - "faye-websocket": "^0.11.3", + "debug": "^3.2.7", + "eventsource": "^1.1.0", + "faye-websocket": "^0.11.4", "inherits": "^2.0.4", - "json3": "^3.3.3", - "url-parse": "^1.5.3" + "url-parse": "^1.5.10" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://tidelift.com/funding/github/npm/sockjs-client" } }, "node_modules/sockjs-client/node_modules/debug": { @@ -22996,11 +23049,11 @@ "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" }, "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, "node_modules/source-map-js": { @@ -23307,11 +23360,11 @@ } }, "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/stealthy-require": { @@ -23409,17 +23462,17 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/string.prototype.matchall": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz", - "integrity": "sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", + "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==", "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", "es-abstract": "^1.19.1", "get-intrinsic": "^1.1.1", - "has-symbols": "^1.0.2", + "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.3.1", + "regexp.prototype.flags": "^1.4.1", "side-channel": "^1.0.4" }, "funding": { @@ -23427,24 +23480,26 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -23919,9 +23974,9 @@ } }, "node_modules/table/node_modules/ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -24060,9 +24115,9 @@ } }, "node_modules/terser-webpack-plugin/node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", "bin": { "acorn": "bin/acorn" }, @@ -24238,13 +24293,13 @@ } }, "node_modules/terser-webpack-plugin/node_modules/terser": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.11.0.tgz", - "integrity": "sha512-uCA9DLanzzWSsN1UirKwylhhRz3aKPInlfmpGfw8VN6jHsAtu8HJtIpeeHHK23rxnE/cDc+yvmq5wqkIC6Kn0A==", + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.13.1.tgz", + "integrity": "sha512-hn4WKOfwnwbYfe48NgrQjqNOH9jzLqRcIfbYytOXCOv46LBfWr9bDS17MQqOi+BWGD0sJK3Sj5NC/gJjiojaoA==", "dependencies": { "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", + "source-map": "~0.8.0-beta.0", "source-map-support": "~0.5.20" }, "bin": { @@ -24255,13 +24310,39 @@ } }, "node_modules/terser-webpack-plugin/node_modules/terser/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==", + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "dependencies": { + "whatwg-url": "^7.0.0" + }, "engines": { "node": ">= 8" } }, + "node_modules/terser-webpack-plugin/node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "node_modules/terser-webpack-plugin/node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, "node_modules/terser/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -24472,13 +24553,13 @@ } }, "node_modules/tsconfig-paths": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", - "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.1", - "minimist": "^1.2.0", + "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, @@ -24542,11 +24623,11 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, "node_modules/twilio": { - "version": "3.75.0", - "resolved": "https://registry.npmjs.org/twilio/-/twilio-3.75.0.tgz", - "integrity": "sha512-SpBWzxNrqU6lONILdpRyq2otlwpnQhzOE9Gnp/ZruPrncM2GWysTHPxk08RmEsShNsG7UxOQbdsRaIZq2fuPjw==", + "version": "3.76.1", + "resolved": "https://registry.npmjs.org/twilio/-/twilio-3.76.1.tgz", + "integrity": "sha512-/hHTn+XfjG6FEDXeOpOGJO9XzyP5zpDBalZ4g75stAsP0T/yHlGPokfrhKZjQoOZNzeE9UiQfDq2yvcQHXjDfQ==", "dependencies": { - "axios": "^0.25.0", + "axios": "^0.26.1", "dayjs": "^1.8.29", "https-proxy-agent": "^5.0.0", "jsonwebtoken": "^8.5.1", @@ -24555,7 +24636,7 @@ "qs": "^6.9.4", "rootpath": "^0.1.2", "scmp": "^2.1.0", - "url-parse": "^1.5.6", + "url-parse": "^1.5.9", "xmlbuilder": "^13.0.2" }, "engines": { @@ -24563,11 +24644,11 @@ } }, "node_modules/twilio/node_modules/axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", "dependencies": { - "follow-redirects": "^1.14.7" + "follow-redirects": "^1.14.8" } }, "node_modules/twilio/node_modules/q": { @@ -24641,9 +24722,9 @@ } }, "node_modules/typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", "peer": true, "bin": { "tsc": "bin/tsc", @@ -24659,13 +24740,13 @@ "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" }, "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", "which-boxed-primitive": "^1.0.2" }, "funding": { @@ -24971,9 +25052,9 @@ } }, "node_modules/utf-8-validate": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.8.tgz", - "integrity": "sha512-k4dW/Qja1BYDl2qD4tOMB9PFVha/UJtxTc1cXYOe3WwA/2m0Yn4qB7wLMpJyLJ/7DR0XnTut3HsCSzDT4ZvKgA==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.9.tgz", + "integrity": "sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q==", "hasInstallScript": true, "dependencies": { "node-gyp-build": "^4.3.0" @@ -25053,14 +25134,6 @@ "node": ">=10.10.0" } }, - "node_modules/v8-to-istanbul/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==", - "engines": { - "node": ">= 8" - } - }, "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", @@ -25433,27 +25506,27 @@ "integrity": "sha512-lNR9aAefbGPpHO7AEnY0hCFjz1eTkWCXYvkTRrTHs9qv8zJp+SkVYpzfLIFXQQiG3tVvbNFQgVg2bQS8YGgxyw==" }, "node_modules/web3": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3/-/web3-1.7.0.tgz", - "integrity": "sha512-n39O7QQNkpsjhiHMJ/6JY6TaLbdX+2FT5iGs8tb3HbIWOhPm4+a7UDbr5Lkm+gLa9aRKWesZs5D5hWyEvg4aJA==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.7.3.tgz", + "integrity": "sha512-UgBvQnKIXncGYzsiGacaiHtm0xzQ/JtGqcSO/ddzQHYxnNuwI72j1Pb4gskztLYihizV9qPNQYHMSCiBlStI9A==", "hasInstallScript": true, "dependencies": { - "web3-bzz": "1.7.0", - "web3-core": "1.7.0", - "web3-eth": "1.7.0", - "web3-eth-personal": "1.7.0", - "web3-net": "1.7.0", - "web3-shh": "1.7.0", - "web3-utils": "1.7.0" + "web3-bzz": "1.7.3", + "web3-core": "1.7.3", + "web3-eth": "1.7.3", + "web3-eth-personal": "1.7.3", + "web3-net": "1.7.3", + "web3-shh": "1.7.3", + "web3-utils": "1.7.3" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-bzz": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.7.0.tgz", - "integrity": "sha512-XPhTWUnZa8gnARfiqaag3jJ9+6+a66Li8OikgBUJoMUqPuQTCJPncTbGYqOJIfRFGavEAdlMnfYXx9lvgv2ZPw==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.7.3.tgz", + "integrity": "sha512-y2i2IW0MfSqFc1JBhBSQ59Ts9xE30hhxSmLS13jLKWzie24/An5dnoGarp2rFAy20tevJu1zJVPYrEl14jiL5w==", "hasInstallScript": true, "dependencies": { "@types/node": "^12.12.6", @@ -25465,58 +25538,58 @@ } }, "node_modules/web3-bzz/node_modules/@types/node": { - "version": "12.20.46", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.46.tgz", - "integrity": "sha512-cPjLXj8d6anFPzFvOPxS3fvly3Shm5nTfl6g8X5smexixbuGUf7hfr21J5tX9JW+UPStp/5P5R8qrKL5IyVJ+A==" + "version": "12.20.50", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.50.tgz", + "integrity": "sha512-+9axpWx2b2JCVovr7Ilgt96uc6C1zBKOQMpGtRbWT9IoR/8ue32GGMfGA4woP8QyP2gBs6GQWEVM3tCybGCxDA==" }, "node_modules/web3-core": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.7.0.tgz", - "integrity": "sha512-U/CRL53h3T5KHl8L3njzCBT7fCaHkbE6BGJe3McazvFldRbfTDEHXkUJCyM30ZD0RoLi3aDfTVeFIusmEyCctA==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.7.3.tgz", + "integrity": "sha512-4RNxueGyevD1XSjdHE57vz/YWRHybpcd3wfQS33fgMyHZBVLFDNwhn+4dX4BeofVlK/9/cmPAokLfBUStZMLdw==", "dependencies": { "@types/bn.js": "^4.11.5", "@types/node": "^12.12.6", "bignumber.js": "^9.0.0", - "web3-core-helpers": "1.7.0", - "web3-core-method": "1.7.0", - "web3-core-requestmanager": "1.7.0", - "web3-utils": "1.7.0" + "web3-core-helpers": "1.7.3", + "web3-core-method": "1.7.3", + "web3-core-requestmanager": "1.7.3", + "web3-utils": "1.7.3" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-core-helpers": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.7.0.tgz", - "integrity": "sha512-kFiqsZFHJliKF8VKZNjt2JvKu3gu7h3N1/ke3EPhdp9Li/rLmiyzFVr6ApryZ1FSjbSx6vyOkibG3m6xQ5EHJA==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.7.3.tgz", + "integrity": "sha512-qS2t6UKLhRV/6C7OFHtMeoHphkcA+CKUr2vfpxy4hubs3+Nj28K9pgiqFuvZiXmtEEwIAE2A28GBOC3RdcSuFg==", "dependencies": { - "web3-eth-iban": "1.7.0", - "web3-utils": "1.7.0" + "web3-eth-iban": "1.7.3", + "web3-utils": "1.7.3" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-core-method": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.7.0.tgz", - "integrity": "sha512-43Om+kZX8wU5u1pJ28TltF9e9pSTRph6b8wrOb6wgXAfPHqMulq6UTBJWjXXIRVN46Eiqv0nflw35hp9bbgnbA==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.7.3.tgz", + "integrity": "sha512-SeF8YL/NVFbj/ddwLhJeS0io8y7wXaPYA2AVT0h2C2ESYkpvOtQmyw2Bc3aXxBmBErKcbOJjE2ABOKdUmLSmMA==", "dependencies": { "@ethersproject/transactions": "^5.0.0-beta.135", - "web3-core-helpers": "1.7.0", - "web3-core-promievent": "1.7.0", - "web3-core-subscriptions": "1.7.0", - "web3-utils": "1.7.0" + "web3-core-helpers": "1.7.3", + "web3-core-promievent": "1.7.3", + "web3-core-subscriptions": "1.7.3", + "web3-utils": "1.7.3" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-core-promievent": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.7.0.tgz", - "integrity": "sha512-xPH66XeC0K0k29GoRd0vyPQ07yxERPRd4yVPrbMzGAz/e9E4M3XN//XK6+PdfGvGw3fx8VojS+tNIMiw+PujbQ==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.7.3.tgz", + "integrity": "sha512-+mcfNJLP8h2JqcL/UdMGdRVfTdm+bsoLzAFtLpazE4u9kU7yJUgMMAqnK59fKD3Zpke3DjaUJKwz1TyiGM5wig==", "dependencies": { "eventemitter3": "4.0.4" }, @@ -25530,27 +25603,27 @@ "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==" }, "node_modules/web3-core-requestmanager": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.7.0.tgz", - "integrity": "sha512-rA3dBTBPrt+eIfTAQ2/oYNTN/2wbZaYNR3pFZGqG8+2oCK03+7oQyz4sWISKy/nYQhURh4GK01rs9sN4o/Tq9w==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.7.3.tgz", + "integrity": "sha512-bC+jeOjPbagZi2IuL1J5d44f3zfPcgX+GWYUpE9vicNkPUxFBWRG+olhMo7L+BIcD57cTmukDlnz+1xBULAjFg==", "dependencies": { "util": "^0.12.0", - "web3-core-helpers": "1.7.0", - "web3-providers-http": "1.7.0", - "web3-providers-ipc": "1.7.0", - "web3-providers-ws": "1.7.0" + "web3-core-helpers": "1.7.3", + "web3-providers-http": "1.7.3", + "web3-providers-ipc": "1.7.3", + "web3-providers-ws": "1.7.3" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-core-subscriptions": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.7.0.tgz", - "integrity": "sha512-6giF8pyJrPmWrRpc2WLoVCvQdMMADp20ZpAusEW72axauZCNlW1XfTjs0i4QHQBfdd2lFp65qad9IuATPhuzrQ==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.7.3.tgz", + "integrity": "sha512-/i1ZCLW3SDxEs5mu7HW8KL4Vq7x4/fDXY+yf/vPoDljlpvcLEOnI8y9r7om+0kYwvuTlM6DUHHafvW0221TyRQ==", "dependencies": { "eventemitter3": "4.0.4", - "web3-core-helpers": "1.7.0" + "web3-core-helpers": "1.7.3" }, "engines": { "node": ">=8.0.0" @@ -25562,48 +25635,48 @@ "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==" }, "node_modules/web3-core/node_modules/@types/node": { - "version": "12.20.46", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.46.tgz", - "integrity": "sha512-cPjLXj8d6anFPzFvOPxS3fvly3Shm5nTfl6g8X5smexixbuGUf7hfr21J5tX9JW+UPStp/5P5R8qrKL5IyVJ+A==" + "version": "12.20.50", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.50.tgz", + "integrity": "sha512-+9axpWx2b2JCVovr7Ilgt96uc6C1zBKOQMpGtRbWT9IoR/8ue32GGMfGA4woP8QyP2gBs6GQWEVM3tCybGCxDA==" }, "node_modules/web3-eth": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.7.0.tgz", - "integrity": "sha512-3uYwjMjn/MZjKIzXCt4YL9ja/k9X5shfa4lKparZhZE6uesmu+xmSmrEFXA/e9qcveF50jkV7frjkT8H+cLYtw==", - "dependencies": { - "web3-core": "1.7.0", - "web3-core-helpers": "1.7.0", - "web3-core-method": "1.7.0", - "web3-core-subscriptions": "1.7.0", - "web3-eth-abi": "1.7.0", - "web3-eth-accounts": "1.7.0", - "web3-eth-contract": "1.7.0", - "web3-eth-ens": "1.7.0", - "web3-eth-iban": "1.7.0", - "web3-eth-personal": "1.7.0", - "web3-net": "1.7.0", - "web3-utils": "1.7.0" + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.7.3.tgz", + "integrity": "sha512-BCIRMPwaMlTCbswXyGT6jj9chCh9RirbDFkPtvqozfQ73HGW7kP78TXXf9+Xdo1GjutQfxi/fQ9yPdxtDJEpDA==", + "dependencies": { + "web3-core": "1.7.3", + "web3-core-helpers": "1.7.3", + "web3-core-method": "1.7.3", + "web3-core-subscriptions": "1.7.3", + "web3-eth-abi": "1.7.3", + "web3-eth-accounts": "1.7.3", + "web3-eth-contract": "1.7.3", + "web3-eth-ens": "1.7.3", + "web3-eth-iban": "1.7.3", + "web3-eth-personal": "1.7.3", + "web3-net": "1.7.3", + "web3-utils": "1.7.3" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-eth-abi": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.7.0.tgz", - "integrity": "sha512-heqR0bWxgCJwjWIhq2sGyNj9bwun5+Xox/LdZKe+WMyTSy0cXDXEAgv3XKNkXC4JqdDt/ZlbTEx4TWak4TRMSg==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.7.3.tgz", + "integrity": "sha512-ZlD8DrJro0ocnbZViZpAoMX44x5aYAb73u2tMq557rMmpiluZNnhcCYF/NnVMy6UIkn7SF/qEA45GXA1ne6Tnw==", "dependencies": { "@ethersproject/abi": "5.0.7", - "web3-utils": "1.7.0" + "web3-utils": "1.7.3" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-eth-accounts": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.7.0.tgz", - "integrity": "sha512-Zwm7TlQXdXGRuS6+ib1YsR5fQwpfnFyL6UAZg1zERdrUrs3IkCZSL3yCP/8ZYbAjdTEwWljoott2iSqXNH09ug==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.7.3.tgz", + "integrity": "sha512-aDaWjW1oJeh0LeSGRVyEBiTe/UD2/cMY4dD6pQYa8dOhwgMtNQjxIQ7kacBBXe7ZKhjbIFZDhvXN4mjXZ82R2Q==", "dependencies": { "@ethereumjs/common": "^2.5.0", "@ethereumjs/tx": "^3.3.2", @@ -25612,10 +25685,10 @@ "ethereumjs-util": "^7.0.10", "scrypt-js": "^3.0.1", "uuid": "3.3.2", - "web3-core": "1.7.0", - "web3-core-helpers": "1.7.0", - "web3-core-method": "1.7.0", - "web3-utils": "1.7.0" + "web3-core": "1.7.3", + "web3-core-helpers": "1.7.3", + "web3-core-method": "1.7.3", + "web3-utils": "1.7.3" }, "engines": { "node": ">=8.0.0" @@ -25641,93 +25714,93 @@ } }, "node_modules/web3-eth-contract": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.7.0.tgz", - "integrity": "sha512-2LY1Xwxu5rx468nqHuhvupQAIpytxIUj3mGL9uexszkhrQf05THVe3i4OnUCzkeN6B2cDztNOqLT3j9SSnVQDg==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.7.3.tgz", + "integrity": "sha512-7mjkLxCNMWlQrlfM/MmNnlKRHwFk5XrZcbndoMt3KejcqDP6dPHi2PZLutEcw07n/Sk8OMpSamyF3QiGfmyRxw==", "dependencies": { "@types/bn.js": "^4.11.5", - "web3-core": "1.7.0", - "web3-core-helpers": "1.7.0", - "web3-core-method": "1.7.0", - "web3-core-promievent": "1.7.0", - "web3-core-subscriptions": "1.7.0", - "web3-eth-abi": "1.7.0", - "web3-utils": "1.7.0" + "web3-core": "1.7.3", + "web3-core-helpers": "1.7.3", + "web3-core-method": "1.7.3", + "web3-core-promievent": "1.7.3", + "web3-core-subscriptions": "1.7.3", + "web3-eth-abi": "1.7.3", + "web3-utils": "1.7.3" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-eth-ens": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.7.0.tgz", - "integrity": "sha512-I1bikYJJWQ/FJZIAvwsGOvzAgcRIkosWG4s1L6veRoXaU8OEJFeh4s00KcfHDxg7GWZZGbUSbdbzKpwRbWnvkg==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.7.3.tgz", + "integrity": "sha512-q7+hFGHIc0mBI3LwgRVcLCQmp6GItsWgUtEZ5bjwdjOnJdbjYddm7PO9RDcTDQ6LIr7hqYaY4WTRnDHZ6BEt5Q==", "dependencies": { "content-hash": "^2.5.2", "eth-ens-namehash": "2.0.8", - "web3-core": "1.7.0", - "web3-core-helpers": "1.7.0", - "web3-core-promievent": "1.7.0", - "web3-eth-abi": "1.7.0", - "web3-eth-contract": "1.7.0", - "web3-utils": "1.7.0" + "web3-core": "1.7.3", + "web3-core-helpers": "1.7.3", + "web3-core-promievent": "1.7.3", + "web3-eth-abi": "1.7.3", + "web3-eth-contract": "1.7.3", + "web3-utils": "1.7.3" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-eth-iban": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.7.0.tgz", - "integrity": "sha512-1PFE/Og+sPZaug+M9TqVUtjOtq0HecE+SjDcsOOysXSzslNC2CItBGkcRwbvUcS+LbIkA7MFsuqYxOL0IV/gyA==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.7.3.tgz", + "integrity": "sha512-1GPVWgajwhh7g53mmYDD1YxcftQniIixMiRfOqlnA1w0mFGrTbCoPeVaSQ3XtSf+rYehNJIZAUeDBnONVjXXmg==", "dependencies": { "bn.js": "^4.11.9", - "web3-utils": "1.7.0" + "web3-utils": "1.7.3" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-eth-personal": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.7.0.tgz", - "integrity": "sha512-Dr9RZTNOR80PhrPKGdktDUXpOgExEcCcosBj080lKCJFU1paSPj9Zfnth3u6BtIOXyKsVFTrpqekqUDyAwXnNw==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.7.3.tgz", + "integrity": "sha512-iTLz2OYzEsJj2qGE4iXC1Gw+KZN924fTAl0ESBFs2VmRhvVaM7GFqZz/wx7/XESl3GVxGxlRje3gNK0oGIoYYQ==", "dependencies": { "@types/node": "^12.12.6", - "web3-core": "1.7.0", - "web3-core-helpers": "1.7.0", - "web3-core-method": "1.7.0", - "web3-net": "1.7.0", - "web3-utils": "1.7.0" + "web3-core": "1.7.3", + "web3-core-helpers": "1.7.3", + "web3-core-method": "1.7.3", + "web3-net": "1.7.3", + "web3-utils": "1.7.3" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-eth-personal/node_modules/@types/node": { - "version": "12.20.46", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.46.tgz", - "integrity": "sha512-cPjLXj8d6anFPzFvOPxS3fvly3Shm5nTfl6g8X5smexixbuGUf7hfr21J5tX9JW+UPStp/5P5R8qrKL5IyVJ+A==" + "version": "12.20.50", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.50.tgz", + "integrity": "sha512-+9axpWx2b2JCVovr7Ilgt96uc6C1zBKOQMpGtRbWT9IoR/8ue32GGMfGA4woP8QyP2gBs6GQWEVM3tCybGCxDA==" }, "node_modules/web3-net": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.7.0.tgz", - "integrity": "sha512-8pmfU1Se7DmG40Pu8nOCKlhuI12VsVzCtdFDnLAai0zGVAOUuuOCK71B2aKm6u9amWBJjtOlyrCwvsG+QEd6dw==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.7.3.tgz", + "integrity": "sha512-zAByK0Qrr71k9XW0Adtn+EOuhS9bt77vhBO6epAeQ2/VKl8rCGLAwrl3GbeEl7kWa8s/su72cjI5OetG7cYR0g==", "dependencies": { - "web3-core": "1.7.0", - "web3-core-method": "1.7.0", - "web3-utils": "1.7.0" + "web3-core": "1.7.3", + "web3-core-method": "1.7.3", + "web3-utils": "1.7.3" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-providers-http": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.7.0.tgz", - "integrity": "sha512-Y9reeEiApfvQKLUUtrU4Z0c+H6b7BMWcsxjgoXndI1C5NB297mIUfltXxfXsh5C/jk5qn4Q3sJp3SwQTyVjH7Q==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.7.3.tgz", + "integrity": "sha512-TQJfMsDQ5Uq9zGMYlu7azx1L7EvxW+Llks3MaWn3cazzr5tnrDbGh6V17x6LN4t8tFDHWx0rYKr3mDPqyTjOZw==", "dependencies": { - "web3-core-helpers": "1.7.0", + "web3-core-helpers": "1.7.3", "xhr2-cookies": "1.1.0" }, "engines": { @@ -25735,24 +25808,24 @@ } }, "node_modules/web3-providers-ipc": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.7.0.tgz", - "integrity": "sha512-U5YLXgu6fvAK4nnMYqo9eoml3WywgTym0dgCdVX/n1UegLIQ4nctTubBAuWQEJzmAzwh+a6ValGcE7ZApTRI7Q==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.7.3.tgz", + "integrity": "sha512-Z4EGdLKzz6I1Bw+VcSyqVN4EJiT2uAro48Am1eRvxUi4vktGoZtge1ixiyfrRIVb6nPe7KnTFl30eQBtMqS0zA==", "dependencies": { "oboe": "2.1.5", - "web3-core-helpers": "1.7.0" + "web3-core-helpers": "1.7.3" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-providers-ws": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.7.0.tgz", - "integrity": "sha512-0a8+lVV3JBf+eYnGOsdzOpftK1kis5X7s35QAdoaG5SDapnEylXFlR4xDSSSU88ZwMwvse8hvng2xW6A7oeWxw==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.7.3.tgz", + "integrity": "sha512-PpykGbkkkKtxPgv7U4ny4UhnkqSZDfLgBEvFTXuXLAngbX/qdgfYkhIuz3MiGplfL7Yh93SQw3xDjImXmn2Rgw==", "dependencies": { "eventemitter3": "4.0.4", - "web3-core-helpers": "1.7.0", + "web3-core-helpers": "1.7.3", "websocket": "^1.0.32" }, "engines": { @@ -25765,24 +25838,24 @@ "integrity": "sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ==" }, "node_modules/web3-shh": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.7.0.tgz", - "integrity": "sha512-RZhxcevALIPK178VZCpwMBvQeW+IoWtRJ4EMdegpbnETeZaC3aRUcs6vKnrf0jXJjm4J/E2Dt438Y1Ord/1IMw==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.7.3.tgz", + "integrity": "sha512-bQTSKkyG7GkuULdZInJ0osHjnmkHij9tAySibpev1XjYdjLiQnd0J9YGF4HjvxoG3glNROpuCyTaRLrsLwaZuw==", "hasInstallScript": true, "dependencies": { - "web3-core": "1.7.0", - "web3-core-method": "1.7.0", - "web3-core-subscriptions": "1.7.0", - "web3-net": "1.7.0" + "web3-core": "1.7.3", + "web3-core-method": "1.7.3", + "web3-core-subscriptions": "1.7.3", + "web3-net": "1.7.3" }, "engines": { "node": ">=8.0.0" } }, "node_modules/web3-utils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.7.0.tgz", - "integrity": "sha512-O8Tl4Ky40Sp6pe89Olk2FsaUkgHyb5QAXuaKo38ms3CxZZ4d3rPGfjP9DNKGm5+IUgAZBNpF1VmlSmNCqfDI1w==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.7.3.tgz", + "integrity": "sha512-g6nQgvb/bUpVUIxJE+ezVN+rYwYmlFyMvMIRSuqpi1dk6ApDD00YNArrk7sPcZnjvxOJ76813Xs2vIN2rgh4lg==", "dependencies": { "bn.js": "^4.11.9", "ethereum-bloom-filters": "^1.0.6", @@ -26043,9 +26116,9 @@ } }, "node_modules/webpack-dev-server/node_modules/cliui/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "engines": { "node": ">=6" } @@ -26358,9 +26431,9 @@ } }, "node_modules/webpack-dev-server/node_modules/string-width/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "engines": { "node": ">=6" } @@ -26424,9 +26497,9 @@ } }, "node_modules/webpack-dev-server/node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "engines": { "node": ">=6" } @@ -27101,14 +27174,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/workbox-build/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==", - "engines": { - "node": ">= 8" - } - }, "node_modules/workbox-build/node_modules/universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -27576,11 +27641,12 @@ }, "dependencies": { "@ampproject/remapping": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.1.2.tgz", - "integrity": "sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "requires": { - "@jridgewell/trace-mapping": "^0.3.0" + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" } }, "@babel/code-frame": { @@ -27592,40 +27658,40 @@ } }, "@babel/compat-data": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.0.tgz", - "integrity": "sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==" + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz", + "integrity": "sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==" }, "@babel/core": { - "version": "7.17.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.5.tgz", - "integrity": "sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.10.tgz", + "integrity": "sha512-liKoppandF3ZcBnIYFjfSDHZLKdLHGJRkoWtG8zQyGJBQfIYobpnVGI5+pLBNtS6psFLDzyq8+h5HiVljW9PNA==", "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", - "@babel/helpers": "^7.17.2", - "@babel/parser": "^7.17.3", + "@babel/generator": "^7.17.10", + "@babel/helper-compilation-targets": "^7.17.10", + "@babel/helper-module-transforms": "^7.17.7", + "@babel/helpers": "^7.17.9", + "@babel/parser": "^7.17.10", "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.3", - "@babel/types": "^7.17.0", + "@babel/traverse": "^7.17.10", + "@babel/types": "^7.17.10", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.1.2", + "json5": "^2.2.1", "semver": "^6.3.0" } }, "@babel/generator": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.3.tgz", - "integrity": "sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.10.tgz", + "integrity": "sha512-46MJZZo9y3o4kmhBVc7zW7i8dtR1oIK/sdO5NcfcZRhTGYi+KKJRtHNgsU6c4VUcJmUNV/LQdebD/9Dlv4K+Tg==", "requires": { - "@babel/types": "^7.17.0", - "jsesc": "^2.5.1", - "source-map": "^0.5.0" + "@babel/types": "^7.17.10", + "@jridgewell/gen-mapping": "^0.1.0", + "jsesc": "^2.5.1" } }, "@babel/helper-annotate-as-pure": { @@ -27646,25 +27712,25 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", - "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.10.tgz", + "integrity": "sha512-gh3RxjWbauw/dFiU/7whjd0qN9K6nPJMqe6+Er7rOavFh0CQUSwhAE3IcTho2rywPJFxej6TUUHDkWcYI6gGqQ==", "requires": { - "@babel/compat-data": "^7.16.4", + "@babel/compat-data": "^7.17.10", "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.17.5", + "browserslist": "^4.20.2", "semver": "^6.3.0" } }, "@babel/helper-create-class-features-plugin": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz", - "integrity": "sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.9.tgz", + "integrity": "sha512-kUjip3gruz6AJKOq5i3nC6CoCEEF/oHH3cp6tOZhB+IyyyPyW0g1Gfsxn3mkk6S08pIA2y8GQh609v9G/5sHVQ==", "requires": { "@babel/helper-annotate-as-pure": "^7.16.7", "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", + "@babel/helper-member-expression-to-functions": "^7.17.7", "@babel/helper-optimise-call-expression": "^7.16.7", "@babel/helper-replace-supers": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7" @@ -27711,21 +27777,12 @@ } }, "@babel/helper-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", - "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", + "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", "requires": { - "@babel/helper-get-function-arity": "^7.16.7", "@babel/template": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", - "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", - "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" } }, "@babel/helper-hoist-variables": { @@ -27737,11 +27794,11 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz", - "integrity": "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz", + "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==", "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" } }, "@babel/helper-module-imports": { @@ -27753,13 +27810,13 @@ } }, "@babel/helper-module-transforms": { - "version": "7.17.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz", - "integrity": "sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz", + "integrity": "sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw==", "requires": { "@babel/helper-environment-visitor": "^7.16.7", "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", "@babel/helper-split-export-declaration": "^7.16.7", "@babel/helper-validator-identifier": "^7.16.7", "@babel/template": "^7.16.7", @@ -27803,11 +27860,11 @@ } }, "@babel/helper-simple-access": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", - "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz", + "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==", "requires": { - "@babel/types": "^7.16.7" + "@babel/types": "^7.17.0" } }, "@babel/helper-skip-transparent-expression-wrappers": { @@ -27848,19 +27905,19 @@ } }, "@babel/helpers": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.2.tgz", - "integrity": "sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.9.tgz", + "integrity": "sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q==", "requires": { "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.0", + "@babel/traverse": "^7.17.9", "@babel/types": "^7.17.0" } }, "@babel/highlight": { - "version": "7.16.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.10.tgz", - "integrity": "sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.17.9.tgz", + "integrity": "sha512-J9PfEKCbFIv2X5bjTMiZu6Vf341N05QIY+d6FvVKynkG1S7G0j3I0QoRtWIrXhZ+/Nlb5Q0MzqL7TokEJ5BNHg==", "requires": { "@babel/helper-validator-identifier": "^7.16.7", "chalk": "^2.0.0", @@ -27868,9 +27925,9 @@ } }, "@babel/parser": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.3.tgz", - "integrity": "sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==" + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.10.tgz", + "integrity": "sha512-n2Q6i+fnJqzOaq2VkdXxy2TCPCWQZHiCo0XqmrCvDWcZQKRyZzYi4Z0yxlBuN0w+r2ZHmre+Q087DSrw3pbJDQ==" }, "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { "version": "7.16.7", @@ -27920,13 +27977,14 @@ } }, "@babel/plugin-proposal-decorators": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.2.tgz", - "integrity": "sha512-WH8Z95CwTq/W8rFbMqb9p3hicpt4RX4f0K659ax2VHxgOyT6qQmUaEVEjIh4WR9Eh9NymkVn5vwsrE68fAQNUw==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.17.9.tgz", + "integrity": "sha512-EfH2LZ/vPa2wuPwJ26j+kYRkaubf89UlwxKXtxqEm57HrgSEYDB8t4swFP+p8LcI9yiP9ZRJJjo/58hS6BnaDA==", "requires": { - "@babel/helper-create-class-features-plugin": "^7.17.1", + "@babel/helper-create-class-features-plugin": "^7.17.9", "@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-replace-supers": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", "@babel/plugin-syntax-decorators": "^7.17.0", "charcodes": "^0.2.0" } @@ -28198,9 +28256,9 @@ } }, "@babel/plugin-syntax-typescript": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz", - "integrity": "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.17.10.tgz", + "integrity": "sha512-xJefea1DWXW09pW4Tm9bjwVlPDyYA2it3fWlmEjpYz6alPvTUjL0EOzNzI/FEOyI3r4/J7uVH5UqKgl1TQ5hqQ==", "requires": { "@babel/helper-plugin-utils": "^7.16.7" } @@ -28263,9 +28321,9 @@ } }, "@babel/plugin-transform-destructuring": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.3.tgz", - "integrity": "sha512-dDFzegDYKlPqa72xIlbmSkly5MluLoaC1JswABGktyt6NTXSBcUuse/kWE/wvKFWJHPETpi158qJZFS3JmykJg==", + "version": "7.17.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz", + "integrity": "sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ==", "requires": { "@babel/helper-plugin-utils": "^7.16.7" } @@ -28350,23 +28408,23 @@ } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz", - "integrity": "sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.9.tgz", + "integrity": "sha512-2TBFd/r2I6VlYn0YRTz2JdazS+FoUuQ2rIFHoAxtyP/0G3D82SBLaRq9rnUkpqlLg03Byfl/+M32mpxjO6KaPw==", "requires": { - "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-module-transforms": "^7.17.7", "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-simple-access": "^7.17.7", "babel-plugin-dynamic-import-node": "^2.3.3" } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz", - "integrity": "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw==", + "version": "7.17.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.8.tgz", + "integrity": "sha512-39reIkMTUVagzgA5x88zDYXPCMT6lcaRKs1+S9K6NKBPErbgO/w/kP8GlNQTC87b412ZTlmNgr3k2JrWgHH+Bw==", "requires": { "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.16.7", + "@babel/helper-module-transforms": "^7.17.7", "@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-validator-identifier": "^7.16.7", "babel-plugin-dynamic-import-node": "^2.3.3" @@ -28382,11 +28440,11 @@ } }, "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz", - "integrity": "sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.17.10.tgz", + "integrity": "sha512-v54O6yLaJySCs6mGzaVOUw9T967GnH38T6CQSAtnzdNPwu84l2qAjssKzo/WSO8Yi7NF+7ekm5cVbF/5qiIgNA==", "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7" + "@babel/helper-create-regexp-features-plugin": "^7.17.0" } }, "@babel/plugin-transform-new-target": { @@ -28468,11 +28526,11 @@ } }, "@babel/plugin-transform-regenerator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz", - "integrity": "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.17.9.tgz", + "integrity": "sha512-Lc2TfbxR1HOyn/c6b4Y/b6NHoTb67n/IoWLxTu4kC7h4KQnWlhCq2S8Tx0t2SVvv5Uu87Hs+6JEJ5kt2tYGylQ==", "requires": { - "regenerator-transform": "^0.14.2" + "regenerator-transform": "^0.15.0" } }, "@babel/plugin-transform-reserved-words": { @@ -28484,9 +28542,9 @@ } }, "@babel/plugin-transform-runtime": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.17.0.tgz", - "integrity": "sha512-fr7zPWnKXNc1xoHfrIU9mN/4XKX4VLZ45Q+oMhfsYIaHvg7mHgmhfOy/ckRWqDK7XF3QDigRpkh5DKq6+clE8A==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.17.10.tgz", + "integrity": "sha512-6jrMilUAJhktTr56kACL8LnWC5hx3Lf27BS0R0DSyW/OoJfb/iTHeE96V3b1dgKG3FSFdd/0culnYWMkjcKCig==", "requires": { "@babel/helper-module-imports": "^7.16.7", "@babel/helper-plugin-utils": "^7.16.7", @@ -28565,26 +28623,26 @@ } }, "@babel/preset-env": { - "version": "7.16.11", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.11.tgz", - "integrity": "sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.17.10.tgz", + "integrity": "sha512-YNgyBHZQpeoBSRBg0xixsZzfT58Ze1iZrajvv0lJc70qDDGuGfonEnMGfWeSY0mQ3JTuCWFbMkzFRVafOyJx4g==", "requires": { - "@babel/compat-data": "^7.16.8", - "@babel/helper-compilation-targets": "^7.16.7", + "@babel/compat-data": "^7.17.10", + "@babel/helper-compilation-targets": "^7.17.10", "@babel/helper-plugin-utils": "^7.16.7", "@babel/helper-validator-option": "^7.16.7", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.16.7", "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.16.7", "@babel/plugin-proposal-async-generator-functions": "^7.16.8", "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/plugin-proposal-class-static-block": "^7.16.7", + "@babel/plugin-proposal-class-static-block": "^7.17.6", "@babel/plugin-proposal-dynamic-import": "^7.16.7", "@babel/plugin-proposal-export-namespace-from": "^7.16.7", "@babel/plugin-proposal-json-strings": "^7.16.7", "@babel/plugin-proposal-logical-assignment-operators": "^7.16.7", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.7", "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.16.7", + "@babel/plugin-proposal-object-rest-spread": "^7.17.3", "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", "@babel/plugin-proposal-optional-chaining": "^7.16.7", "@babel/plugin-proposal-private-methods": "^7.16.11", @@ -28610,7 +28668,7 @@ "@babel/plugin-transform-block-scoping": "^7.16.7", "@babel/plugin-transform-classes": "^7.16.7", "@babel/plugin-transform-computed-properties": "^7.16.7", - "@babel/plugin-transform-destructuring": "^7.16.7", + "@babel/plugin-transform-destructuring": "^7.17.7", "@babel/plugin-transform-dotall-regex": "^7.16.7", "@babel/plugin-transform-duplicate-keys": "^7.16.7", "@babel/plugin-transform-exponentiation-operator": "^7.16.7", @@ -28619,15 +28677,15 @@ "@babel/plugin-transform-literals": "^7.16.7", "@babel/plugin-transform-member-expression-literals": "^7.16.7", "@babel/plugin-transform-modules-amd": "^7.16.7", - "@babel/plugin-transform-modules-commonjs": "^7.16.8", - "@babel/plugin-transform-modules-systemjs": "^7.16.7", + "@babel/plugin-transform-modules-commonjs": "^7.17.9", + "@babel/plugin-transform-modules-systemjs": "^7.17.8", "@babel/plugin-transform-modules-umd": "^7.16.7", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.16.8", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.17.10", "@babel/plugin-transform-new-target": "^7.16.7", "@babel/plugin-transform-object-super": "^7.16.7", "@babel/plugin-transform-parameters": "^7.16.7", "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.16.7", + "@babel/plugin-transform-regenerator": "^7.17.9", "@babel/plugin-transform-reserved-words": "^7.16.7", "@babel/plugin-transform-shorthand-properties": "^7.16.7", "@babel/plugin-transform-spread": "^7.16.7", @@ -28637,11 +28695,11 @@ "@babel/plugin-transform-unicode-escapes": "^7.16.7", "@babel/plugin-transform-unicode-regex": "^7.16.7", "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.16.8", + "@babel/types": "^7.17.10", "babel-plugin-polyfill-corejs2": "^0.3.0", "babel-plugin-polyfill-corejs3": "^0.5.0", "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.20.2", + "core-js-compat": "^3.22.1", "semver": "^6.3.0" } }, @@ -28681,17 +28739,17 @@ } }, "@babel/runtime": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz", - "integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", + "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", "requires": { "regenerator-runtime": "^0.13.4" } }, "@babel/runtime-corejs3": { - "version": "7.17.2", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.2.tgz", - "integrity": "sha512-NcKtr2epxfIrNM4VOmPKO46TvDMCBhgi2CrSHaEarrz+Plk2K5r9QemmOFTGpZaoKnWoGH5MO+CzeRsih/Fcgg==", + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.17.9.tgz", + "integrity": "sha512-WxYHHUWF2uZ7Hp1K+D1xQgbgkGUfA+5UPOegEXGt2Y5SMog/rYCVaifLZDbw8UkNXozEqqrZTy6bglL7xTaCOw==", "requires": { "core-js-pure": "^3.20.2", "regenerator-runtime": "^0.13.4" @@ -28708,26 +28766,26 @@ } }, "@babel/traverse": { - "version": "7.17.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.3.tgz", - "integrity": "sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.10.tgz", + "integrity": "sha512-VmbrTHQteIdUUQNTb+zE12SHS/xQVIShmBPhlNP12hD5poF2pbITW1Z4172d03HegaQWhLffdkRJYtAzp0AGcw==", "requires": { "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.3", + "@babel/generator": "^7.17.10", "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", + "@babel/helper-function-name": "^7.17.9", "@babel/helper-hoist-variables": "^7.16.7", "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.3", - "@babel/types": "^7.17.0", + "@babel/parser": "^7.17.10", + "@babel/types": "^7.17.10", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.17.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.0.tgz", - "integrity": "sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==", + "version": "7.17.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.10.tgz", + "integrity": "sha512-9O26jG0mBYfGkUYCYZRnBwbVLd1UZOICEr2Em6InB6jVfsAv1GKgwXHmrSg+WFWDmeKTA6vyTZiN8tCSM5Oo3A==", "requires": { "@babel/helper-validator-identifier": "^7.16.7", "to-fast-properties": "^2.0.0" @@ -28779,9 +28837,9 @@ }, "dependencies": { "globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", "requires": { "type-fest": "^0.20.2" } @@ -28794,20 +28852,20 @@ } }, "@ethereumjs/common": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.6.2.tgz", - "integrity": "sha512-vDwye5v0SVeuDky4MtKsu+ogkH2oFUV8pBKzH/eNBzT8oI91pKa8WyzDuYuxOQsgNgv5R34LfFDh2aaw3H4HbQ==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.6.4.tgz", + "integrity": "sha512-RDJh/R/EAr+B7ZRg5LfJ0BIpf/1LydFgYdvZEuTraojCbVypO2sQ+QnpP5u2wJf9DASyooKqu8O4FJEWUV6NXw==", "requires": { "crc-32": "^1.2.0", "ethereumjs-util": "^7.1.4" } }, "@ethereumjs/tx": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.5.0.tgz", - "integrity": "sha512-/+ZNbnJhQhXC83Xuvy6I9k4jT5sXiV0tMR9C+AzSSpcCV64+NB8dTE1m3x98RYMqb8+TLYWA+HML4F5lfXTlJw==", + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.5.1.tgz", + "integrity": "sha512-xzDrTiu4sqZXUcaBxJ4n4W5FrppwxLxZB4ZDGVLtxSQR4lVuOnFR6RcUHdg1mpUhAPVrmnzLJpxaeXnPxIyhWA==", "requires": { - "@ethereumjs/common": "^2.6.1", + "@ethereumjs/common": "^2.6.3", "ethereumjs-util": "^7.1.4" } }, @@ -28828,180 +28886,180 @@ } }, "@ethersproject/abstract-provider": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.5.1.tgz", - "integrity": "sha512-m+MA/ful6eKbxpr99xUYeRvLkfnlqzrF8SZ46d/xFB1A7ZVknYc/sXJG0RcufF52Qn2jeFj1hhcoQ7IXjNKUqg==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.6.0.tgz", + "integrity": "sha512-oPMFlKLN+g+y7a79cLK3WiLcjWFnZQtXWgnLAbHZcN3s7L4v90UHpTOrLk+m3yr0gt+/h9STTM6zrr7PM8uoRw==", "requires": { - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/networks": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "@ethersproject/transactions": "^5.5.0", - "@ethersproject/web": "^5.5.0" + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/networks": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/transactions": "^5.6.0", + "@ethersproject/web": "^5.6.0" } }, "@ethersproject/abstract-signer": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.5.0.tgz", - "integrity": "sha512-lj//7r250MXVLKI7sVarXAbZXbv9P50lgmJQGr2/is82EwEb8r7HrxsmMqAjTsztMYy7ohrIhGMIml+Gx4D3mA==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.6.0.tgz", + "integrity": "sha512-WOqnG0NJKtI8n0wWZPReHtaLkDByPL67tn4nBaDAhmVq8sjHTPbCdz4DRhVu/cfTOvfy9w3iq5QZ7BX7zw56BQ==", "requires": { - "@ethersproject/abstract-provider": "^5.5.0", - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/properties": "^5.5.0" + "@ethersproject/abstract-provider": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0" } }, "@ethersproject/address": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.5.0.tgz", - "integrity": "sha512-l4Nj0eWlTUh6ro5IbPTgbpT4wRbdH5l8CQf7icF7sb/SI3Nhd9Y9HzhonTSTi6CefI0necIw7LJqQPopPLZyWw==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.6.0.tgz", + "integrity": "sha512-6nvhYXjbXsHPS+30sHZ+U4VMagFC/9zAk6Gd/h3S21YW4+yfb0WfRtaAIZ4kfM4rrVwqiy284LP0GtL5HXGLxQ==", "requires": { - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/keccak256": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/rlp": "^5.5.0" + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/rlp": "^5.6.0" } }, "@ethersproject/base64": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.5.0.tgz", - "integrity": "sha512-tdayUKhU1ljrlHzEWbStXazDpsx4eg1dBXUSI6+mHlYklOXoXF6lZvw8tnD6oVaWfnMxAgRSKROg3cVKtCcppA==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.6.0.tgz", + "integrity": "sha512-2Neq8wxJ9xHxCF9TUgmKeSh9BXJ6OAxWfeGWvbauPh8FuHEjamgHilllx8KkSd5ErxyHIX7Xv3Fkcud2kY9ezw==", "requires": { - "@ethersproject/bytes": "^5.5.0" + "@ethersproject/bytes": "^5.6.0" } }, "@ethersproject/bignumber": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.5.0.tgz", - "integrity": "sha512-6Xytlwvy6Rn3U3gKEc1vP7nR92frHkv6wtVr95LFR3jREXiCPzdWxKQ1cx4JGQBXxcguAwjA8murlYN2TSiEbg==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.6.0.tgz", + "integrity": "sha512-VziMaXIUHQlHJmkv1dlcd6GY2PmT0khtAqaMctCIDogxkrarMzA9L94KN1NeXqqOfFD6r0sJT3vCTOFSmZ07DA==", "requires": { - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", "bn.js": "^4.11.9" } }, "@ethersproject/bytes": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.5.0.tgz", - "integrity": "sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.6.1.tgz", + "integrity": "sha512-NwQt7cKn5+ZE4uDn+X5RAXLp46E1chXoaMmrxAyA0rblpxz8t58lVkrHXoRIn0lz1joQElQ8410GqhTqMOwc6g==", "requires": { - "@ethersproject/logger": "^5.5.0" + "@ethersproject/logger": "^5.6.0" } }, "@ethersproject/constants": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.5.0.tgz", - "integrity": "sha512-2MsRRVChkvMWR+GyMGY4N1sAX9Mt3J9KykCsgUFd/1mwS0UH1qw+Bv9k1UJb3X3YJYFco9H20pjSlOIfCG5HYQ==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.6.0.tgz", + "integrity": "sha512-SrdaJx2bK0WQl23nSpV/b1aq293Lh0sUaZT/yYKPDKn4tlAbkH96SPJwIhwSwTsoQQZxuh1jnqsKwyymoiBdWA==", "requires": { - "@ethersproject/bignumber": "^5.5.0" + "@ethersproject/bignumber": "^5.6.0" } }, "@ethersproject/hash": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.5.0.tgz", - "integrity": "sha512-dnGVpK1WtBjmnp3mUT0PlU2MpapnwWI0PibldQEq1408tQBAbZpPidkWoVVuNMOl/lISO3+4hXZWCL3YV7qzfg==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.6.0.tgz", + "integrity": "sha512-fFd+k9gtczqlr0/BruWLAu7UAOas1uRRJvOR84uDf4lNZ+bTkGl366qvniUZHKtlqxBRU65MkOobkmvmpHU+jA==", "requires": { - "@ethersproject/abstract-signer": "^5.5.0", - "@ethersproject/address": "^5.5.0", - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/keccak256": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "@ethersproject/strings": "^5.5.0" + "@ethersproject/abstract-signer": "^5.6.0", + "@ethersproject/address": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/strings": "^5.6.0" } }, "@ethersproject/keccak256": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.5.0.tgz", - "integrity": "sha512-5VoFCTjo2rYbBe1l2f4mccaRFN/4VQEYFwwn04aJV2h7qf4ZvI2wFxUE1XOX+snbwCLRzIeikOqtAoPwMza9kg==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.6.0.tgz", + "integrity": "sha512-tk56BJ96mdj/ksi7HWZVWGjCq0WVl/QvfhFQNeL8fxhBlGoP+L80uDCiQcpJPd+2XxkivS3lwRm3E0CXTfol0w==", "requires": { - "@ethersproject/bytes": "^5.5.0", + "@ethersproject/bytes": "^5.6.0", "js-sha3": "0.8.0" } }, "@ethersproject/logger": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.5.0.tgz", - "integrity": "sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg==" + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.6.0.tgz", + "integrity": "sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg==" }, "@ethersproject/networks": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.5.2.tgz", - "integrity": "sha512-NEqPxbGBfy6O3x4ZTISb90SjEDkWYDUbEeIFhJly0F7sZjoQMnj5KYzMSkMkLKZ+1fGpx00EDpHQCy6PrDupkQ==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.6.2.tgz", + "integrity": "sha512-9uEzaJY7j5wpYGTojGp8U89mSsgQLc40PCMJLMCnFXTs7nhBveZ0t7dbqWUNrepWTszDbFkYD6WlL8DKx5huHA==", "requires": { - "@ethersproject/logger": "^5.5.0" + "@ethersproject/logger": "^5.6.0" } }, "@ethersproject/properties": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.5.0.tgz", - "integrity": "sha512-l3zRQg3JkD8EL3CPjNK5g7kMx4qSwiR60/uk5IVjd3oq1MZR5qUg40CNOoEJoX5wc3DyY5bt9EbMk86C7x0DNA==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.6.0.tgz", + "integrity": "sha512-szoOkHskajKePTJSZ46uHUWWkbv7TzP2ypdEK6jGMqJaEt2sb0jCgfBo0gH0m2HBpRixMuJ6TBRaQCF7a9DoCg==", "requires": { - "@ethersproject/logger": "^5.5.0" + "@ethersproject/logger": "^5.6.0" } }, "@ethersproject/rlp": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.5.0.tgz", - "integrity": "sha512-hLv8XaQ8PTI9g2RHoQGf/WSxBfTB/NudRacbzdxmst5VHAqd1sMibWG7SENzT5Dj3yZ3kJYx+WiRYEcQTAkcYA==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.6.0.tgz", + "integrity": "sha512-dz9WR1xpcTL+9DtOT/aDO+YyxSSdO8YIS0jyZwHHSlAmnxA6cKU3TrTd4Xc/bHayctxTgGLYNuVVoiXE4tTq1g==", "requires": { - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0" + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0" } }, "@ethersproject/signing-key": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.5.0.tgz", - "integrity": "sha512-5VmseH7qjtNmDdZBswavhotYbWB0bOwKIlOTSlX14rKn5c11QmJwGt4GHeo7NrL/Ycl7uo9AHvEqs5xZgFBTng==", + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.6.1.tgz", + "integrity": "sha512-XvqQ20DH0D+bS3qlrrgh+axRMth5kD1xuvqUQUTeezxUTXBOeR6hWz2/C6FBEu39FRytyybIWrYf7YLSAKr1LQ==", "requires": { - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/properties": "^5.5.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", "bn.js": "^4.11.9", "elliptic": "6.5.4", "hash.js": "1.1.7" } }, "@ethersproject/strings": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.5.0.tgz", - "integrity": "sha512-9fy3TtF5LrX/wTrBaT8FGE6TDJyVjOvXynXJz5MT5azq+E6D92zuKNx7i29sWW2FjVOaWjAsiZ1ZWznuduTIIQ==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.6.0.tgz", + "integrity": "sha512-uv10vTtLTZqrJuqBZR862ZQjTIa724wGPWQqZrofaPI/kUsf53TBG0I0D+hQ1qyNtllbNzaW+PDPHHUI6/65Mg==", "requires": { - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/constants": "^5.5.0", - "@ethersproject/logger": "^5.5.0" + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/constants": "^5.6.0", + "@ethersproject/logger": "^5.6.0" } }, "@ethersproject/transactions": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.5.0.tgz", - "integrity": "sha512-9RZYSKX26KfzEd/1eqvv8pLauCKzDTub0Ko4LfIgaERvRuwyaNV78mJs7cpIgZaDl6RJui4o49lHwwCM0526zA==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.6.0.tgz", + "integrity": "sha512-4HX+VOhNjXHZyGzER6E/LVI2i6lf9ejYeWD6l4g50AdmimyuStKc39kvKf1bXWQMg7QNVh+uC7dYwtaZ02IXeg==", "requires": { - "@ethersproject/address": "^5.5.0", - "@ethersproject/bignumber": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/constants": "^5.5.0", - "@ethersproject/keccak256": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "@ethersproject/rlp": "^5.5.0", - "@ethersproject/signing-key": "^5.5.0" + "@ethersproject/address": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/constants": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/rlp": "^5.6.0", + "@ethersproject/signing-key": "^5.6.0" } }, "@ethersproject/web": { - "version": "5.5.1", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.5.1.tgz", - "integrity": "sha512-olvLvc1CB12sREc1ROPSHTdFCdvMh0J5GSJYiQg2D0hdD4QmJDy8QYDb1CvoqD/bF1c++aeKv2sR5uduuG9dQg==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.6.0.tgz", + "integrity": "sha512-G/XHj0hV1FxI2teHRfCGvfBUHFmU+YOSbCxlAMqJklxSa7QMiHFQfAxvwY2PFqgvdkxEKwRNr/eCjfAPEm2Ctg==", "requires": { - "@ethersproject/base64": "^5.5.0", - "@ethersproject/bytes": "^5.5.0", - "@ethersproject/logger": "^5.5.0", - "@ethersproject/properties": "^5.5.0", - "@ethersproject/strings": "^5.5.0" + "@ethersproject/base64": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/strings": "^5.6.0" } }, "@gar/promisify": { @@ -29604,34 +29662,48 @@ } } }, + "@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==", + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@jridgewell/resolve-uri": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", - "integrity": "sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==" + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.6.tgz", + "integrity": "sha512-R7xHtBSNm+9SyvpJkdQl+qrM3Hm2fea3Ef197M3mUug+v+yR+Rhfbs7PBtcBUVnIWJ4JcAdjvij+c8hXS9p5aw==" + }, + "@jridgewell/set-array": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.0.tgz", + "integrity": "sha512-SfJxIxNVYLTsKwzB3MoOQ1yxf4w/E6MdkvTgrgAt1bfxjSrLUoHMKrDOykwN14q65waezZIdqDneUIPh4/sKxg==" }, "@jridgewell/sourcemap-codec": { - "version": "1.4.11", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz", - "integrity": "sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==" + "version": "1.4.12", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.12.tgz", + "integrity": "sha512-az/NhpIwP3K33ILr0T2bso+k2E/SLf8Yidd8mHl0n6sCQ4YdyC8qDhZA6kOPDNDBA56ZnIjngVl0U3jREA0BUA==" }, "@jridgewell/trace-mapping": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz", - "integrity": "sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==", + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "requires": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" } }, "@mapbox/node-pre-gyp": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.8.tgz", - "integrity": "sha512-CMGKi28CF+qlbXh26hDe6NxCd7amqeAzEqnS6IHeO6LoaKyM/n+Xw3HT1COdq8cuioOdlKdqn/hCmqPUOMOywg==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.9.tgz", + "integrity": "sha512-aDF3S3rK9Q2gey/WAttUlISduDItz5BU3306M9Eyv6/oS40aMprnopshtlKTykxRNIBEZuRMaZAnbrQ4QtKGyw==", "requires": { - "detect-libc": "^1.0.3", + "detect-libc": "^2.0.0", "https-proxy-agent": "^5.0.0", "make-dir": "^3.1.0", - "node-fetch": "^2.6.5", + "node-fetch": "^2.6.7", "nopt": "^5.0.0", "npmlog": "^5.0.1", "rimraf": "^3.0.2", @@ -29640,9 +29712,9 @@ }, "dependencies": { "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "requires": { "lru-cache": "^6.0.0" } @@ -29650,15 +29722,15 @@ } }, "@material-ui/core": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.3.tgz", - "integrity": "sha512-sdpgI/PL56QVsEJldwEe4FFaFTLUqN+rd7sSZiRCdx2E/C7z5yK0y/khAWVBH24tXwto7I1hCzNWfJGZIYJKnw==", + "version": "4.12.4", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.4.tgz", + "integrity": "sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ==", "requires": { "@babel/runtime": "^7.4.4", - "@material-ui/styles": "^4.11.4", - "@material-ui/system": "^4.12.1", + "@material-ui/styles": "^4.11.5", + "@material-ui/system": "^4.12.2", "@material-ui/types": "5.1.0", - "@material-ui/utils": "^4.11.2", + "@material-ui/utils": "^4.11.3", "@types/react-transition-group": "^4.2.0", "clsx": "^1.0.4", "hoist-non-react-statics": "^3.3.2", @@ -29666,100 +29738,60 @@ "prop-types": "^15.7.2", "react-is": "^16.8.0 || ^17.0.0", "react-transition-group": "^4.4.0" - }, - "dependencies": { - "@material-ui/styles": { - "version": "4.11.4", - "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.4.tgz", - "integrity": "sha512-KNTIZcnj/zprG5LW0Sao7zw+yG3O35pviHzejMdcSGCdWbiO8qzRgOYL8JAxAsWBKOKYwVZxXtHWaB5T2Kvxew==", - "requires": { - "@babel/runtime": "^7.4.4", - "@emotion/hash": "^0.8.0", - "@material-ui/types": "5.1.0", - "@material-ui/utils": "^4.11.2", - "clsx": "^1.0.4", - "csstype": "^2.5.2", - "hoist-non-react-statics": "^3.3.2", - "jss": "^10.5.1", - "jss-plugin-camel-case": "^10.5.1", - "jss-plugin-default-unit": "^10.5.1", - "jss-plugin-global": "^10.5.1", - "jss-plugin-nested": "^10.5.1", - "jss-plugin-props-sort": "^10.5.1", - "jss-plugin-rule-value-function": "^10.5.1", - "jss-plugin-vendor-prefixer": "^10.5.1", - "prop-types": "^15.7.2" - } - }, - "@material-ui/system": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.1.tgz", - "integrity": "sha512-lUdzs4q9kEXZGhbN7BptyiS1rLNHe6kG9o8Y307HCvF4sQxbCgpL2qi+gUk+yI8a2DNk48gISEQxoxpgph0xIw==", - "requires": { - "@babel/runtime": "^7.4.4", - "@material-ui/utils": "^4.11.2", - "csstype": "^2.5.2", - "prop-types": "^15.7.2" - } - }, - "@material-ui/utils": { - "version": "4.11.2", - "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz", - "integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==", - "requires": { - "@babel/runtime": "^7.4.4", - "prop-types": "^15.7.2", - "react-is": "^16.8.0 || ^17.0.0" - } - }, - "csstype": { - "version": "2.6.19", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.19.tgz", - "integrity": "sha512-ZVxXaNy28/k3kJg0Fou5MiYpp88j7H9hLZp8PDC3jV0WFjfH5E9xHb56L0W59cPbKbcHXeP4qyT8PrHp8t6LcQ==" - }, - "react-transition-group": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", - "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", - "requires": { - "@babel/runtime": "^7.5.5", - "dom-helpers": "^5.0.1", - "loose-envify": "^1.4.0", - "prop-types": "^15.6.2" - } - } } }, "@material-ui/icons": { - "version": "4.11.2", - "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.2.tgz", - "integrity": "sha512-fQNsKX2TxBmqIGJCSi3tGTO/gZ+eJgWmMJkgDiOfyNaunNaxcklJQFaFogYcFl0qFuaEz1qaXYXboa/bUXVSOQ==", + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.3.tgz", + "integrity": "sha512-IKHlyx6LDh8n19vzwH5RtHIOHl9Tu90aAAxcbWME6kp4dmvODM3UvOHJeMIDzUbd4muuJKHmlNoBN+mDY4XkBA==", "requires": { "@babel/runtime": "^7.4.4" } }, "@material-ui/lab": { - "version": "4.0.0-alpha.60", - "resolved": "https://registry.npmjs.org/@material-ui/lab/-/lab-4.0.0-alpha.60.tgz", - "integrity": "sha512-fadlYsPJF+0fx2lRuyqAuJj7hAS1tLDdIEEdov5jlrpb5pp4b+mRDUqQTUxi4inRZHS1bEXpU8QWUhO6xX88aA==", + "version": "4.0.0-alpha.61", + "resolved": "https://registry.npmjs.org/@material-ui/lab/-/lab-4.0.0-alpha.61.tgz", + "integrity": "sha512-rSzm+XKiNUjKegj8bzt5+pygZeckNLOr+IjykH8sYdVk7dE9y2ZuUSofiMV2bJk3qU+JHwexmw+q0RyNZB9ugg==", "requires": { "@babel/runtime": "^7.4.4", - "@material-ui/utils": "^4.11.2", + "@material-ui/utils": "^4.11.3", "clsx": "^1.0.4", "prop-types": "^15.7.2", "react-is": "^16.8.0 || ^17.0.0" - }, - "dependencies": { - "@material-ui/utils": { - "version": "4.11.2", - "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.2.tgz", - "integrity": "sha512-Uul8w38u+PICe2Fg2pDKCaIG7kOyhowZ9vjiC1FsVwPABTW8vPPKfF6OvxRq3IiBaI1faOJmgdvMG7rMJARBhA==", - "requires": { - "@babel/runtime": "^7.4.4", - "prop-types": "^15.7.2", - "react-is": "^16.8.0 || ^17.0.0" - } - } + } + }, + "@material-ui/styles": { + "version": "4.11.5", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.5.tgz", + "integrity": "sha512-o/41ot5JJiUsIETME9wVLAJrmIWL3j0R0Bj2kCOLbSfqEkKf0fmaPt+5vtblUh5eXr2S+J/8J3DaCb10+CzPGA==", + "requires": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.3", + "clsx": "^1.0.4", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.5.1", + "jss-plugin-camel-case": "^10.5.1", + "jss-plugin-default-unit": "^10.5.1", + "jss-plugin-global": "^10.5.1", + "jss-plugin-nested": "^10.5.1", + "jss-plugin-props-sort": "^10.5.1", + "jss-plugin-rule-value-function": "^10.5.1", + "jss-plugin-vendor-prefixer": "^10.5.1", + "prop-types": "^15.7.2" + } + }, + "@material-ui/system": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.2.tgz", + "integrity": "sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.11.3", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" } }, "@material-ui/types": { @@ -29768,6 +29800,16 @@ "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==", "requires": {} }, + "@material-ui/utils": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.3.tgz", + "integrity": "sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==", + "requires": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -29801,9 +29843,9 @@ }, "dependencies": { "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "requires": { "lru-cache": "^6.0.0" } @@ -29837,13 +29879,6 @@ "native-url": "^0.2.6", "schema-utils": "^2.6.5", "source-map": "^0.7.3" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" - } } }, "@rollup/plugin-node-resolve": { @@ -29919,15 +29954,15 @@ "integrity": "sha512-0k8UlVEH9gUVwTbwcanS1JT2vCROkr1WESgdXW7d2maWYTuwbVEx87YvXPjsemAJfdu+RYqxGhO2oGTigprepA==" }, "@slack/web-api": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/@slack/web-api/-/web-api-6.7.0.tgz", - "integrity": "sha512-Jd0ZC/aolkdeM2m3j0SYASlzoUe1AWgm19eDkmGjfli6CzoW1benYHqgMh1owS7+gLfe4FEILtE0fyVDZjgmGQ==", + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/@slack/web-api/-/web-api-6.7.1.tgz", + "integrity": "sha512-Aa2E/7NtGagd7mVsFCrc69iZMoviR2032SBOic06sYVvptdzJlvNsSQVqLCb1Aqz7r/jodb2fnXO1gl016OcWQ==", "requires": { "@slack/logger": "^3.0.0", "@slack/types": "^2.0.0", "@types/is-stream": "^1.1.0", "@types/node": ">=12.0.0", - "axios": "^0.25.0", + "axios": "^0.26.1", "eventemitter3": "^3.1.0", "form-data": "^2.5.0", "is-electron": "2.2.0", @@ -29937,11 +29972,11 @@ }, "dependencies": { "axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", "requires": { - "follow-redirects": "^1.14.7" + "follow-redirects": "^1.14.8" } } } @@ -30085,9 +30120,9 @@ "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==" }, "@types/babel__core": { - "version": "7.1.18", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", - "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz", + "integrity": "sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==", "requires": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0", @@ -30114,9 +30149,9 @@ } }, "@types/babel__traverse": { - "version": "7.14.2", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz", - "integrity": "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==", + "version": "7.17.1", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.17.1.tgz", + "integrity": "sha512-kVzjari1s2YVi77D3w1yuvohV2idweYXMCDzqBiVNN63TcDWrIlTVOYpqVrvbbyOE/IyzBoTKF0fdnLPEORFxA==", "requires": { "@babel/types": "^7.3.0" } @@ -30204,9 +30239,9 @@ } }, "@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==" + "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==" }, "@types/json5": { "version": "0.0.29", @@ -30219,9 +30254,9 @@ "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==" }, "@types/node": { - "version": "17.0.21", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", - "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==" + "version": "17.0.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.31.tgz", + "integrity": "sha512-AR0x5HbXGqkEx9CadRH3EBYx/VkiUgZIhP4wvPn/+5KIsgpNoyFaRlVe0Zlx9gRtg8fA06a9tskE2MSN7TcG4Q==" }, "@types/normalize-package-data": { "version": "2.4.1", @@ -30242,14 +30277,14 @@ } }, "@types/prettier": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.4.tgz", - "integrity": "sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA==" + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.6.0.tgz", + "integrity": "sha512-G/AdOadiZhnJp0jXCaBQU449W2h716OW/EoXeYkCytxKL06X1WCXB4DZpp8TpZ8eyIJVS1cw4lrlkkSYU21cDw==" }, "@types/prop-types": { - "version": "15.7.4", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz", - "integrity": "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==" + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" }, "@types/q": { "version": "1.5.5", @@ -30257,28 +30292,35 @@ "integrity": "sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==" }, "@types/react": { - "version": "16.14.23", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.23.tgz", - "integrity": "sha512-WngBZLuSkP4IAgPi0HOsGCHo6dn3CcuLQnCfC17VbA7YBgipZiZoTOhObwl/93DsFW0Y2a/ZXeonpW4DxirEJg==", + "version": "16.14.25", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.25.tgz", + "integrity": "sha512-cXRVHd7vBT5v1is72mmvmsg9stZrbJO04DJqFeh3Yj2tVKO6vmxg5BI+ybI6Ls7ROXRG3aFbZj9x0WA3ZAoDQw==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", "csstype": "^3.0.2" + }, + "dependencies": { + "csstype": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", + "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" + } } }, "@types/react-dom": { - "version": "16.9.14", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.14.tgz", - "integrity": "sha512-FIX2AVmPTGP30OUJ+0vadeIFJJ07Mh1m+U0rxfgyW34p3rTlXI+nlenvAxNn4BP36YyI9IJ/+UJ7Wu22N1pI7A==", + "version": "16.9.15", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.15.tgz", + "integrity": "sha512-PjWhZj54ACucQX2hDmnHyqHz+N2On5g3Lt5BeNn+wy067qvOokVSQw1nEog1XGfvLYrSl3cyrdebEfjQQNXD3A==", "peer": true, "requires": { "@types/react": "^16" } }, "@types/react-redux": { - "version": "7.1.22", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.22.tgz", - "integrity": "sha512-GxIA1kM7ClU73I6wg9IRTVwSO9GS+SAKZKe0Enj+82HMU6aoESFU2HNAdNi3+J53IaOHPiUfT3kSG4L828joDQ==", + "version": "7.1.24", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.24.tgz", + "integrity": "sha512-7FkurKcS1k0FHZEtdbbgN8Oc6b+stGSfZYjQGicofJ0j4U0qIn/jaSvnP2pLwZKiai3/17xqqxkkrxTgN8UNbQ==", "requires": { "@types/hoist-non-react-statics": "^3.3.0", "@types/react": "*", @@ -30303,9 +30345,9 @@ } }, "@types/retry": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", - "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==" + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" }, "@types/scheduler": { "version": "0.16.2", @@ -30336,9 +30378,9 @@ "integrity": "sha512-ipixuVrh2OdNmauvtT51o3d8z12p6LtFW9in7U79der/kwejjdNchQC5UMn5u/KxNoM7VHHOs/l8KS8uHxhODQ==" }, "@types/uglify-js": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.1.tgz", - "integrity": "sha512-O3MmRAk6ZuAKa9CHgg0Pr0+lUOqoMLpc9AS4R8ano2auvsg7IE8syF3Xh/NPr26TWklxYcqoEEFdzLLs1fV9PQ==", + "version": "3.13.2", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.2.tgz", + "integrity": "sha512-/xFrPIo+4zOeNGtVMbf9rUm0N+i4pDf1ynExomqtokIJmVzR3962lJ1UE+MmexMkA0cmN9oTzg5Xcbwge0Ij2Q==", "requires": { "source-map": "^0.6.1" }, @@ -30378,13 +30420,6 @@ "@types/node": "*", "@types/source-list-map": "*", "source-map": "^0.7.3" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" - } } }, "@types/yargs": { @@ -30396,9 +30431,9 @@ } }, "@types/yargs-parser": { - "version": "20.2.1", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz", - "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==" + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" }, "@typescript-eslint/eslint-plugin": { "version": "4.33.0", @@ -30421,9 +30456,9 @@ "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==" }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "requires": { "lru-cache": "^6.0.0" } @@ -30493,9 +30528,9 @@ }, "dependencies": { "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "requires": { "lru-cache": "^6.0.0" } @@ -30679,9 +30714,9 @@ "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, "abab": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", - "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==" + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==" }, "abbrev": { "version": "1.1.1", @@ -30913,13 +30948,13 @@ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, "array-includes": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", - "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", + "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", "get-intrinsic": "^1.1.1", "is-string": "^1.0.7" } @@ -30940,33 +30975,36 @@ "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" }, "array.prototype.find": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.1.2.tgz", - "integrity": "sha512-00S1O4ewO95OmmJW7EesWfQlrCrLEL8kZ40w3+GkLX2yTt0m2ggcePPa2uHPJ9KUmJvwRq+lCV9bD8Yim23x/Q==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/array.prototype.find/-/array.prototype.find-2.2.0.tgz", + "integrity": "sha512-sn40qmUiLYAcRb/1HsIQjTTZ1kCy8II8VtZJpMn2Aoen9twULhbWXisfh3HimGqMlHGUul0/TfKCnXg42LuPpQ==", "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "es-abstract": "^1.19.4", + "es-shim-unscopables": "^1.0.0" } }, "array.prototype.flat": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", - "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" } }, "array.prototype.flatmap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz", - "integrity": "sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz", + "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==", "requires": { - "call-bind": "^1.0.0", + "call-bind": "^1.0.2", "define-properties": "^1.1.3", - "es-abstract": "^1.19.0" + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" } }, "arrify": { @@ -31043,9 +31081,9 @@ "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" }, "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "requires": { "lodash": "^4.17.14" } @@ -31529,9 +31567,9 @@ } }, "blakejs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.1.1.tgz", - "integrity": "sha512-bLG6PHOCZJKNshTjGRBvET0vTciwQE6zFKOKKXPDJfwFBd4Ac0yBfPZqcGvGJap50l7ktvlpFqc2jGVaUgbJgg==" + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" }, "bluebird": { "version": "3.7.2", @@ -31544,20 +31582,22 @@ "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" }, "body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", "requires": { "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.7", - "raw-body": "2.4.3", - "type-is": "~1.6.18" + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "dependencies": { "debug": { @@ -31724,14 +31764,14 @@ } }, "browserslist": { - "version": "4.19.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.3.tgz", - "integrity": "sha512-XK3X4xtKJ+Txj8G5c30B4gsm71s69lqXlkYui4s6EkKxuv49qjYlY6oVd+IFJ73d4YymtM3+djvvt/R/iJwwDg==", + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", "requires": { - "caniuse-lite": "^1.0.30001312", - "electron-to-chromium": "^1.4.71", + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", "escalade": "^3.1.1", - "node-releases": "^2.0.2", + "node-releases": "^2.0.3", "picocolors": "^1.0.0" } }, @@ -31944,9 +31984,9 @@ }, "dependencies": { "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" } } }, @@ -31967,9 +32007,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001312", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001312.tgz", - "integrity": "sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==" + "version": "1.0.30001335", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001335.tgz", + "integrity": "sha512-ddP1Tgm7z2iIxu6QTtbZUv6HJxSaV/PZeSrWFZtbY4JZ69tOeNhBCl3HyRQgeNZKE5AOn1kpV7fhljigy0Ty3w==" }, "capture-exit": { "version": "2.0.0", @@ -32259,9 +32299,9 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "color-string": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz", - "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", "requires": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" @@ -32495,16 +32535,16 @@ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" }, "core-js": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.21.1.tgz", - "integrity": "sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig==" + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.22.4.tgz", + "integrity": "sha512-1uLykR+iOfYja+6Jn/57743gc9n73EWiOnSJJ4ba3B4fOEYDBv25MagmEZBxTp5cWq4b/KPx/l77zgsp28ju4w==" }, "core-js-compat": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.21.1.tgz", - "integrity": "sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g==", + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.4.tgz", + "integrity": "sha512-dIWcsszDezkFZrfm1cnB4f/J85gyhiCpxbgBdohWCDtSVuAaChTSpPV7ldOQf/Xds2U5xCIJZOK82G4ZPAIswA==", "requires": { - "browserslist": "^4.19.1", + "browserslist": "^4.20.3", "semver": "7.0.0" }, "dependencies": { @@ -32516,9 +32556,9 @@ } }, "core-js-pure": { - "version": "3.21.1", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.21.1.tgz", - "integrity": "sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ==" + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.22.4.tgz", + "integrity": "sha512-4iF+QZkpzIz0prAFuepmxwJ2h5t4agvE8WPYqs2mjLJMNNwJOnpch76w2Q7bUfCPEv/V7wpvOfog0w273M+ZSw==" }, "core-util-is": { "version": "1.0.3", @@ -32547,13 +32587,9 @@ } }, "crc-32": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.1.tgz", - "integrity": "sha512-Dn/xm/1vFFgs3nfrpEVScHoIslO9NZRITWGz/1E/St6u4xw99vfZzVkW0OSnzx2h9egej9xwMCEut6sqwokM/w==", - "requires": { - "exit-on-epipe": "~1.0.1", - "printj": "~1.3.1" - } + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==" }, "create-ecdh": { "version": "4.0.4", @@ -32708,9 +32744,9 @@ }, "dependencies": { "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "requires": { "lru-cache": "^6.0.0" } @@ -32726,13 +32762,13 @@ } }, "css-select": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz", - "integrity": "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", + "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==", "requires": { "boolbase": "^1.0.0", - "css-what": "^5.1.0", - "domhandler": "^4.3.0", + "css-what": "^6.0.1", + "domhandler": "^4.3.1", "domutils": "^2.8.0", "nth-check": "^2.0.1" } @@ -32768,9 +32804,9 @@ } }, "css-what": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz", - "integrity": "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==" + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" }, "cssdb": { "version": "4.4.0", @@ -32939,9 +32975,9 @@ } }, "csstype": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz", - "integrity": "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA==" + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" }, "cyclist": { "version": "1.0.1", @@ -33001,14 +33037,14 @@ } }, "dayjs": { - "version": "1.10.7", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz", - "integrity": "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig==" + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.1.tgz", + "integrity": "sha512-ER7EjqVAMkRRsxNCC5YqJ9d9VQYuWdGt7aiH2qA5R5wt8ZmWaP2dLUSIK6y/kVzLMlmh1Tvu5xUf4M/wdGJ5KA==" }, "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { "ms": "2.1.2" } @@ -33154,11 +33190,12 @@ "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" }, "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", "requires": { - "object-keys": "^1.0.12" + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" } }, "define-property": { @@ -33242,9 +33279,9 @@ "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==" }, "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, "des.js": { "version": "1.0.1", @@ -33256,14 +33293,14 @@ } }, "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, "detect-libc": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", - "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", + "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==" }, "detect-newline": { "version": "3.1.0", @@ -33367,12 +33404,19 @@ "requires": { "@babel/runtime": "^7.8.7", "csstype": "^3.0.2" + }, + "dependencies": { + "csstype": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", + "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" + } } }, "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", + "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==", "requires": { "domelementtype": "^2.0.1", "domhandler": "^4.2.0", @@ -33390,9 +33434,9 @@ "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" }, "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" }, "domexception": { "version": "2.0.1", @@ -33410,9 +33454,9 @@ } }, "domhandler": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz", - "integrity": "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz", + "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==", "requires": { "domelementtype": "^2.2.0" } @@ -33437,9 +33481,9 @@ }, "dependencies": { "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" } } }, @@ -33517,9 +33561,9 @@ "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==" }, "electron-to-chromium": { - "version": "1.4.72", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.72.tgz", - "integrity": "sha512-9LkRQwjW6/wnSfevR21a3k8sOJ+XWSH7kkzs9/EUenKmuDkndP3W9y1yCZpOxufwGbX3JV8glZZSDb4o95zwXQ==" + "version": "1.4.132", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.132.tgz", + "integrity": "sha512-JYdZUw/1068NWN+SwXQ7w6Ue0bWYGihvSUNNQwurvcDV/SM7vSiGZ3NuFvFgoEiCs4kB8xs3cX2an3wB7d4TBw==" }, "elliptic": { "version": "6.5.4", @@ -33622,9 +33666,9 @@ } }, "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.5.tgz", + "integrity": "sha512-Aa2G2+Rd3b6kxEUKTF4TaW67czBLyAv3z7VOhYRU50YBx+bbsYZ9xQP4lMNazePuFlybXI0V4MruPos7qUo5fA==", "requires": { "call-bind": "^1.0.2", "es-to-primitive": "^1.2.1", @@ -33632,15 +33676,15 @@ "get-intrinsic": "^1.1.1", "get-symbol-description": "^1.0.0", "has": "^1.0.3", - "has-symbols": "^1.0.2", + "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", + "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", + "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.0", "object-keys": "^1.1.1", "object.assign": "^4.1.2", "string.prototype.trimend": "^1.0.4", @@ -33648,6 +33692,14 @@ "unbox-primitive": "^1.0.1" } }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "requires": { + "has": "^1.0.3" + } + }, "es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -33659,13 +33711,13 @@ } }, "es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "version": "0.10.61", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.61.tgz", + "integrity": "sha512-yFhIqQAzu2Ca2I4SE2Au3rxVfmohU9Y7wqGR+s7+H7krk26NXhIRAZDgqd6xqjCEFUomDEA3/Bo/7fKmIkW1kA==", "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "next-tick": "^1.1.0" } }, "es6-iterator": { @@ -33848,9 +33900,9 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" }, "globals": { - "version": "13.12.1", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.1.tgz", - "integrity": "sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==", + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", "requires": { "type-fest": "^0.20.2" } @@ -33861,9 +33913,9 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "requires": { "lru-cache": "^6.0.0" } @@ -33961,23 +34013,23 @@ } }, "eslint-plugin-import": { - "version": "2.25.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", - "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", "requires": { "array-includes": "^3.1.4", "array.prototype.flat": "^1.2.5", "debug": "^2.6.9", "doctrine": "^2.1.0", "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.2", + "eslint-module-utils": "^2.7.3", "has": "^1.0.3", - "is-core-module": "^2.8.0", + "is-core-module": "^2.8.1", "is-glob": "^4.0.3", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "object.values": "^1.1.5", - "resolve": "^1.20.0", - "tsconfig-paths": "^3.12.0" + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" }, "dependencies": { "debug": { @@ -34031,21 +34083,21 @@ } }, "eslint-plugin-react": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz", - "integrity": "sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==", + "version": "7.29.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.29.4.tgz", + "integrity": "sha512-CVCXajliVh509PcZYRFyu/BoUEz452+jtQJq2b3Bae4v3xBUWPLCmtmBM+ZinG4MzwmxJgJ2M5rMqhqLVn7MtQ==", "requires": { "array-includes": "^3.1.4", "array.prototype.flatmap": "^1.2.5", "doctrine": "^2.1.0", "estraverse": "^5.3.0", "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.0.4", + "minimatch": "^3.1.2", "object.entries": "^1.1.5", "object.fromentries": "^2.0.5", "object.hasown": "^1.1.0", "object.values": "^1.1.5", - "prop-types": "^15.7.2", + "prop-types": "^15.8.1", "resolve": "^2.0.0-next.3", "semver": "^6.3.0", "string.prototype.matchall": "^4.0.6" @@ -34071,9 +34123,9 @@ } }, "eslint-plugin-react-hooks": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz", - "integrity": "sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.5.0.tgz", + "integrity": "sha512-8k1gRt7D7h03kd+SAAlzXkQwWK22BnK6GKZG+FJA6BAGy22CFvl8kCIXKpVux0cCxMWDQUPqSok0LKaZ0aOcCw==", "requires": {} }, "eslint-plugin-testing-library": { @@ -34130,9 +34182,9 @@ "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "requires": { "lru-cache": "^6.0.0" } @@ -34432,11 +34484,6 @@ "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=" }, - "exit-on-epipe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz", - "integrity": "sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw==" - }, "expand-brackets": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", @@ -34575,46 +34622,47 @@ } }, "express": { - "version": "4.17.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.3.tgz", - "integrity": "sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", + "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.2", + "body-parser": "1.20.0", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.2", + "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "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.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", - "qs": "6.9.7", + "qs": "6.10.3", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", + "send": "0.18.0", + "serve-static": "1.15.0", "setprototypeof": "1.2.0", - "statuses": "~1.5.0", + "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" }, "dependencies": { "cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==" + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" }, "debug": { "version": "2.6.9", @@ -34813,16 +34861,16 @@ } }, "finalhandler": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", - "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", "requires": { "debug": "2.6.9", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "statuses": "~1.5.0", + "statuses": "2.0.1", "unpipe": "~1.0.0" }, "dependencies": { @@ -34909,9 +34957,9 @@ "integrity": "sha512-eNMNr5exLoavuAMhIUVsOKF79SWd/zG104ef6sxBTSw+cZc6BXdQXDvYcGvp0VbxVVSp1XDUNoz7mg1xMtSznA==" }, "follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.0.tgz", + "integrity": "sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==" }, "for-in": { "version": "1.0.2", @@ -35163,9 +35211,9 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" }, "functions-have-names": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.2.tgz", - "integrity": "sha512-bLgc3asbWdwPbx2mNk2S49kmJCuQeu0nfmaOgbs8WIyzzkw3r4htszdIi9Q9EMezDPTYuJx2wvjZ/EwgAthpnA==" + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==" }, "g": { "version": "2.0.1", @@ -35360,9 +35408,9 @@ } }, "graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, "growly": { "version": "1.3.0", @@ -35412,24 +35460,32 @@ } }, "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==" }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "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==", + "requires": { + "get-intrinsic": "^1.1.1" + } + }, "has-symbol-support-x": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==" }, "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, "has-to-string-tag-x": { "version": "1.4.1", @@ -35691,14 +35747,14 @@ "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=" }, "http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "requires": { - "depd": "~1.1.2", + "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", + "statuses": "2.0.1", "toidentifier": "1.0.1" } }, @@ -35708,9 +35764,9 @@ "integrity": "sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs=" }, "http-parser-js": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.5.tgz", - "integrity": "sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA==" + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.6.tgz", + "integrity": "sha512-vDlkRPDJn93swjcjqMSaGSPABbIarsr1TLAui/gLDXzV5VsJNdXNzMYDyNBLQkjWQCJ1uizu8T2oDMhmGt0PRA==" }, "http-proxy": { "version": "1.18.1", @@ -35868,9 +35924,9 @@ "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" }, "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "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==", "requires": { "agent-base": "6", "debug": "4" @@ -36197,9 +36253,9 @@ } }, "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", + "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", "requires": { "has": "^1.0.3" } @@ -36315,9 +36371,9 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" }, "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", "requires": { "has-tostringtag": "^1.0.0" } @@ -36401,9 +36457,12 @@ "integrity": "sha512-AGOriNp96vNBd3HtU+RzFEc75FfR5ymiYv8E553I71SCeXBiMsVDUtdio1OEFvrPyLIQ9tVR5RxXIFe5PUFjMg==" }, "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "requires": { + "call-bind": "^1.0.2" + } }, "is-stream": { "version": "1.1.0", @@ -36490,9 +36549,9 @@ "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==" }, "istanbul-lib-instrument": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz", - "integrity": "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", "requires": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -37568,9 +37627,9 @@ } }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "requires": { "lru-cache": "^6.0.0" } @@ -37903,9 +37962,9 @@ }, "dependencies": { "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==" + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==" }, "form-data": { "version": "3.0.1", @@ -37977,18 +38036,10 @@ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, - "json3": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", - "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==" - }, "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "requires": { - "minimist": "^1.2.5" - } + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", + "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" }, "jsonfile": { "version": "6.1.0", @@ -38043,6 +38094,13 @@ "csstype": "^3.0.2", "is-in-browser": "^1.1.3", "tiny-warning": "^1.0.2" + }, + "dependencies": { + "csstype": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", + "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" + } } }, "jss-plugin-camel-case": { @@ -38113,11 +38171,11 @@ } }, "jsx-ast-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz", - "integrity": "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.0.tgz", + "integrity": "sha512-XzO9luP6L0xkxwhIJMTJQpZo/eeN60K08jHdexfD569AGxeNug6UketeHXEhROoM8aR7EcUoOQmIhcJQjcuq8Q==", "requires": { - "array-includes": "^3.1.3", + "array-includes": "^3.1.4", "object.assign": "^4.1.2" } }, @@ -38325,6 +38383,11 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" + }, "lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -38374,9 +38437,9 @@ }, "dependencies": { "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" } } }, @@ -38394,11 +38457,11 @@ } }, "magic-string": { - "version": "0.25.7", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", - "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==", + "version": "0.25.9", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", + "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", "requires": { - "sourcemap-codec": "^1.4.4" + "sourcemap-codec": "^1.4.8" } }, "make-dir": { @@ -38491,12 +38554,12 @@ "integrity": "sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==" }, "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, "miller-rabin": { @@ -38514,16 +38577,16 @@ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" }, "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==" + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" }, "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "requires": { - "mime-db": "1.51.0" + "mime-db": "1.52.0" } }, "mimic-fn": { @@ -38604,9 +38667,9 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "minipass": { "version": "3.1.6", @@ -38676,11 +38739,11 @@ } }, "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "requires": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" } }, "mkdirp-promise": { @@ -38806,9 +38869,9 @@ "integrity": "sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18=" }, "nanoid": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", - "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==" + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" }, "nanomatch": { "version": "1.2.13", @@ -38852,9 +38915,9 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" }, "nice-try": { "version": "1.0.5", @@ -38871,9 +38934,9 @@ }, "dependencies": { "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" } } }, @@ -38896,9 +38959,9 @@ "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==" }, "node-gyp-build": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz", - "integrity": "sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==" + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", + "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==" }, "node-int64": { "version": "0.4.0", @@ -38980,9 +39043,9 @@ }, "dependencies": { "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "optional": true, "requires": { "lru-cache": "^6.0.0" @@ -39011,14 +39074,14 @@ } }, "node-releases": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", - "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", + "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==" }, "nodemailer": { - "version": "6.7.2", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.2.tgz", - "integrity": "sha512-Dz7zVwlef4k5R71fdmxwR8Q39fiboGbu3xgswkzGwczUfjp873rVxt1O46+Fh0j1ORnAC6L9+heI8uUpO6DT7Q==" + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.7.5.tgz", + "integrity": "sha512-6VtMpwhsrixq1HDYSBBHvW0GwiWawE75dS3oal48VqRhUvKJNnKnJo2RI/bCVQubj1vgrgscMNW4DHaD6xtMCg==" }, "nopt": { "version": "5.0.0", @@ -41146,9 +41209,9 @@ "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" }, "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "requires": { "ee-first": "1.1.1" } @@ -41305,11 +41368,11 @@ } }, "p-retry": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz", - "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "requires": { - "@types/retry": "^0.12.0", + "@types/retry": "0.12.0", "retry": "^0.13.1" } }, @@ -41351,9 +41414,9 @@ }, "dependencies": { "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" } } }, @@ -41378,9 +41441,9 @@ } }, "parse-headers": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.4.tgz", - "integrity": "sha512-psZ9iZoCNFLrgRjZ1d8mn0h9WRqJwFxM9q3x7iUjN/YT2OksthDJ5TiPCu2F38kS4zutqfW+YdVVkBZZx3/1aw==" + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", + "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==" }, "parse-json": { "version": "5.2.0", @@ -41421,9 +41484,9 @@ }, "dependencies": { "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" } } }, @@ -42570,11 +42633,11 @@ }, "dependencies": { "postcss": { - "version": "8.4.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz", - "integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==", + "version": "8.4.13", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.13.tgz", + "integrity": "sha512-jtL6eTBrza5MPzy8oJLFuUscHDXTV5KcLlqAWHl5q5WYRfnNRGSmOZmOZ1T6Gy7A99mOZfqungmZMpMmCVJ8ZA==", "requires": { - "nanoid": "^3.2.0", + "nanoid": "^3.3.3", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } @@ -42600,9 +42663,9 @@ } }, "postcss-selector-parser": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", - "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", "requires": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -42708,11 +42771,6 @@ } } }, - "printj": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/printj/-/printj-1.3.1.tgz", - "integrity": "sha512-GA3TdL8szPK4AQ2YnOe/b+Y1jUFwmmGMMK/qbY7VcE3Z7FU8JstbKiKRzO6CIiAKPhTO8m01NoQ0V5f3jc4OGg==" - }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -42855,9 +42913,12 @@ "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=" }, "qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==" + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "requires": { + "side-channel": "^1.0.4" + } }, "query-string": { "version": "6.13.6", @@ -42920,12 +42981,12 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.3.tgz", - "integrity": "sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "requires": { "bytes": "3.1.2", - "http-errors": "1.8.1", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } @@ -43106,9 +43167,9 @@ } }, "react-error-overlay": { - "version": "6.0.10", - "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.10.tgz", - "integrity": "sha512-mKR90fX7Pm5seCOfz8q9F+66VCc1PGsWSBxKbITjfKVQHMNF2zudxHnMdJiB1fRCb+XsbQV9sO9DCkgsMQgBIA==" + "version": "6.0.11", + "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", + "integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==" }, "react-fast-compare": { "version": "2.0.4", @@ -43121,9 +43182,9 @@ "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" }, "react-redux": { - "version": "7.2.6", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz", - "integrity": "sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ==", + "version": "7.2.8", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.8.tgz", + "integrity": "sha512-6+uDjhs3PSIclqoCk0kd6iX74gzrGc3W5zcAjbrFgEdIjRSQObdIwfx80unTkVUYvbQ95Y8Av3OvFHq1w5EOUw==", "requires": { "@babel/runtime": "^7.15.4", "@types/react-redux": "^7.1.20", @@ -43252,6 +43313,11 @@ "version": "7.3.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" } } }, @@ -43263,6 +43329,17 @@ "watchable-stores": "^2.0.2" } }, + "react-transition-group": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", + "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + }, "read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -43383,9 +43460,9 @@ } }, "redux": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz", - "integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz", + "integrity": "sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==", "requires": { "@babel/runtime": "^7.9.2" } @@ -43420,9 +43497,9 @@ "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" }, "regenerator-transform": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", - "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", + "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", "requires": { "@babel/runtime": "^7.8.4" } @@ -43442,12 +43519,13 @@ "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==" }, "regexp.prototype.flags": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", - "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" } }, "regexpp": { @@ -44220,9 +44298,9 @@ } }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "requires": { "lru-cache": "^6.0.0" } @@ -44307,23 +44385,23 @@ "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" }, "send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "requires": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "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": "1.8.1", + "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "2.0.1" }, "dependencies": { "debug": { @@ -44378,6 +44456,11 @@ "ms": "2.0.0" } }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, "http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", @@ -44403,18 +44486,23 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" } } }, "serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.2" + "send": "0.18.0" } }, "servify": { @@ -44695,6 +44783,11 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" } } }, @@ -44747,16 +44840,15 @@ } }, "sockjs-client": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.5.2.tgz", - "integrity": "sha512-ZzRxPBISQE7RpzlH4tKJMQbHM9pabHluk0WBaxAQ+wm/UieeBVBou0p4wVnSQGN9QmpAZygQ0cDIypWuqOFmFQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.6.0.tgz", + "integrity": "sha512-qVHJlyfdHFht3eBFZdKEXKTlb7I4IV41xnVNo8yUKA1UHcPJwgW2SvTq9LhnjjCywSkSK7c/e4nghU0GOoMCRQ==", "requires": { - "debug": "^3.2.6", - "eventsource": "^1.0.7", - "faye-websocket": "^0.11.3", + "debug": "^3.2.7", + "eventsource": "^1.1.0", + "faye-websocket": "^0.11.4", "inherits": "^2.0.4", - "json3": "^3.3.3", - "url-parse": "^1.5.3" + "url-parse": "^1.5.10" }, "dependencies": { "debug": { @@ -44783,9 +44875,9 @@ "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" }, "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" }, "source-map-js": { "version": "1.0.2", @@ -45042,9 +45134,9 @@ } }, "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" }, "stealthy-require": { "version": "1.1.1", @@ -45131,36 +45223,38 @@ } }, "string.prototype.matchall": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz", - "integrity": "sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", + "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==", "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3", "es-abstract": "^1.19.1", "get-intrinsic": "^1.1.1", - "has-symbols": "^1.0.2", + "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", - "regexp.prototype.flags": "^1.3.1", + "regexp.prototype.flags": "^1.4.1", "side-channel": "^1.0.4" } }, "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" } }, "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" } }, "stringify-object": { @@ -45529,9 +45623,9 @@ }, "dependencies": { "ajv": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.10.0.tgz", - "integrity": "sha512-bzqAEZOjkrUMl2afH8dknrq5KEk2SrwdBROR+vH1EKVQTqaUbJVPdc/gEdggTMM0Se+s+Ja4ju4TlNcStKl2Hw==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", "requires": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", @@ -45641,9 +45735,9 @@ }, "dependencies": { "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==" + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==" }, "commander": { "version": "2.20.3", @@ -45760,22 +45854,48 @@ } }, "terser": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.11.0.tgz", - "integrity": "sha512-uCA9DLanzzWSsN1UirKwylhhRz3aKPInlfmpGfw8VN6jHsAtu8HJtIpeeHHK23rxnE/cDc+yvmq5wqkIC6Kn0A==", + "version": "5.13.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.13.1.tgz", + "integrity": "sha512-hn4WKOfwnwbYfe48NgrQjqNOH9jzLqRcIfbYytOXCOv46LBfWr9bDS17MQqOi+BWGD0sJK3Sj5NC/gJjiojaoA==", "requires": { "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", + "source-map": "~0.8.0-beta.0", "source-map-support": "~0.5.20" }, "dependencies": { "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", + "requires": { + "whatwg-url": "^7.0.0" + } } } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "requires": { + "punycode": "^2.1.0" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" + }, + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } } } }, @@ -45936,13 +46056,13 @@ "integrity": "sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==" }, "tsconfig-paths": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", - "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", "requires": { "@types/json5": "^0.0.29", "json5": "^1.0.1", - "minimist": "^1.2.0", + "minimist": "^1.2.6", "strip-bom": "^3.0.0" }, "dependencies": { @@ -45993,11 +46113,11 @@ "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, "twilio": { - "version": "3.75.0", - "resolved": "https://registry.npmjs.org/twilio/-/twilio-3.75.0.tgz", - "integrity": "sha512-SpBWzxNrqU6lONILdpRyq2otlwpnQhzOE9Gnp/ZruPrncM2GWysTHPxk08RmEsShNsG7UxOQbdsRaIZq2fuPjw==", + "version": "3.76.1", + "resolved": "https://registry.npmjs.org/twilio/-/twilio-3.76.1.tgz", + "integrity": "sha512-/hHTn+XfjG6FEDXeOpOGJO9XzyP5zpDBalZ4g75stAsP0T/yHlGPokfrhKZjQoOZNzeE9UiQfDq2yvcQHXjDfQ==", "requires": { - "axios": "^0.25.0", + "axios": "^0.26.1", "dayjs": "^1.8.29", "https-proxy-agent": "^5.0.0", "jsonwebtoken": "^8.5.1", @@ -46006,16 +46126,16 @@ "qs": "^6.9.4", "rootpath": "^0.1.2", "scmp": "^2.1.0", - "url-parse": "^1.5.6", + "url-parse": "^1.5.9", "xmlbuilder": "^13.0.2" }, "dependencies": { "axios": { - "version": "0.25.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz", - "integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==", + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", "requires": { - "follow-redirects": "^1.14.7" + "follow-redirects": "^1.14.8" } }, "q": { @@ -46076,9 +46196,9 @@ } }, "typescript": { - "version": "4.5.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", - "integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==", + "version": "4.6.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", + "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", "peer": true }, "ultron": { @@ -46087,13 +46207,13 @@ "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==" }, "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", "which-boxed-primitive": "^1.0.2" } }, @@ -46325,9 +46445,9 @@ "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" }, "utf-8-validate": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.8.tgz", - "integrity": "sha512-k4dW/Qja1BYDl2qD4tOMB9PFVha/UJtxTc1cXYOe3WwA/2m0Yn4qB7wLMpJyLJ/7DR0XnTut3HsCSzDT4ZvKgA==", + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.9.tgz", + "integrity": "sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q==", "requires": { "node-gyp-build": "^4.3.0" } @@ -46392,13 +46512,6 @@ "@types/istanbul-lib-coverage": "^2.0.1", "convert-source-map": "^1.6.0", "source-map": "^0.7.3" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" - } } }, "validate-npm-package-license": { @@ -46719,23 +46832,23 @@ "integrity": "sha512-lNR9aAefbGPpHO7AEnY0hCFjz1eTkWCXYvkTRrTHs9qv8zJp+SkVYpzfLIFXQQiG3tVvbNFQgVg2bQS8YGgxyw==" }, "web3": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3/-/web3-1.7.0.tgz", - "integrity": "sha512-n39O7QQNkpsjhiHMJ/6JY6TaLbdX+2FT5iGs8tb3HbIWOhPm4+a7UDbr5Lkm+gLa9aRKWesZs5D5hWyEvg4aJA==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3/-/web3-1.7.3.tgz", + "integrity": "sha512-UgBvQnKIXncGYzsiGacaiHtm0xzQ/JtGqcSO/ddzQHYxnNuwI72j1Pb4gskztLYihizV9qPNQYHMSCiBlStI9A==", "requires": { - "web3-bzz": "1.7.0", - "web3-core": "1.7.0", - "web3-eth": "1.7.0", - "web3-eth-personal": "1.7.0", - "web3-net": "1.7.0", - "web3-shh": "1.7.0", - "web3-utils": "1.7.0" + "web3-bzz": "1.7.3", + "web3-core": "1.7.3", + "web3-eth": "1.7.3", + "web3-eth-personal": "1.7.3", + "web3-net": "1.7.3", + "web3-shh": "1.7.3", + "web3-utils": "1.7.3" } }, "web3-bzz": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.7.0.tgz", - "integrity": "sha512-XPhTWUnZa8gnARfiqaag3jJ9+6+a66Li8OikgBUJoMUqPuQTCJPncTbGYqOJIfRFGavEAdlMnfYXx9lvgv2ZPw==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-bzz/-/web3-bzz-1.7.3.tgz", + "integrity": "sha512-y2i2IW0MfSqFc1JBhBSQ59Ts9xE30hhxSmLS13jLKWzie24/An5dnoGarp2rFAy20tevJu1zJVPYrEl14jiL5w==", "requires": { "@types/node": "^12.12.6", "got": "9.6.0", @@ -46743,58 +46856,58 @@ }, "dependencies": { "@types/node": { - "version": "12.20.46", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.46.tgz", - "integrity": "sha512-cPjLXj8d6anFPzFvOPxS3fvly3Shm5nTfl6g8X5smexixbuGUf7hfr21J5tX9JW+UPStp/5P5R8qrKL5IyVJ+A==" + "version": "12.20.50", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.50.tgz", + "integrity": "sha512-+9axpWx2b2JCVovr7Ilgt96uc6C1zBKOQMpGtRbWT9IoR/8ue32GGMfGA4woP8QyP2gBs6GQWEVM3tCybGCxDA==" } } }, "web3-core": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.7.0.tgz", - "integrity": "sha512-U/CRL53h3T5KHl8L3njzCBT7fCaHkbE6BGJe3McazvFldRbfTDEHXkUJCyM30ZD0RoLi3aDfTVeFIusmEyCctA==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-core/-/web3-core-1.7.3.tgz", + "integrity": "sha512-4RNxueGyevD1XSjdHE57vz/YWRHybpcd3wfQS33fgMyHZBVLFDNwhn+4dX4BeofVlK/9/cmPAokLfBUStZMLdw==", "requires": { "@types/bn.js": "^4.11.5", "@types/node": "^12.12.6", "bignumber.js": "^9.0.0", - "web3-core-helpers": "1.7.0", - "web3-core-method": "1.7.0", - "web3-core-requestmanager": "1.7.0", - "web3-utils": "1.7.0" + "web3-core-helpers": "1.7.3", + "web3-core-method": "1.7.3", + "web3-core-requestmanager": "1.7.3", + "web3-utils": "1.7.3" }, "dependencies": { "@types/node": { - "version": "12.20.46", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.46.tgz", - "integrity": "sha512-cPjLXj8d6anFPzFvOPxS3fvly3Shm5nTfl6g8X5smexixbuGUf7hfr21J5tX9JW+UPStp/5P5R8qrKL5IyVJ+A==" + "version": "12.20.50", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.50.tgz", + "integrity": "sha512-+9axpWx2b2JCVovr7Ilgt96uc6C1zBKOQMpGtRbWT9IoR/8ue32GGMfGA4woP8QyP2gBs6GQWEVM3tCybGCxDA==" } } }, "web3-core-helpers": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.7.0.tgz", - "integrity": "sha512-kFiqsZFHJliKF8VKZNjt2JvKu3gu7h3N1/ke3EPhdp9Li/rLmiyzFVr6ApryZ1FSjbSx6vyOkibG3m6xQ5EHJA==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-core-helpers/-/web3-core-helpers-1.7.3.tgz", + "integrity": "sha512-qS2t6UKLhRV/6C7OFHtMeoHphkcA+CKUr2vfpxy4hubs3+Nj28K9pgiqFuvZiXmtEEwIAE2A28GBOC3RdcSuFg==", "requires": { - "web3-eth-iban": "1.7.0", - "web3-utils": "1.7.0" + "web3-eth-iban": "1.7.3", + "web3-utils": "1.7.3" } }, "web3-core-method": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.7.0.tgz", - "integrity": "sha512-43Om+kZX8wU5u1pJ28TltF9e9pSTRph6b8wrOb6wgXAfPHqMulq6UTBJWjXXIRVN46Eiqv0nflw35hp9bbgnbA==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-core-method/-/web3-core-method-1.7.3.tgz", + "integrity": "sha512-SeF8YL/NVFbj/ddwLhJeS0io8y7wXaPYA2AVT0h2C2ESYkpvOtQmyw2Bc3aXxBmBErKcbOJjE2ABOKdUmLSmMA==", "requires": { "@ethersproject/transactions": "^5.0.0-beta.135", - "web3-core-helpers": "1.7.0", - "web3-core-promievent": "1.7.0", - "web3-core-subscriptions": "1.7.0", - "web3-utils": "1.7.0" + "web3-core-helpers": "1.7.3", + "web3-core-promievent": "1.7.3", + "web3-core-subscriptions": "1.7.3", + "web3-utils": "1.7.3" } }, "web3-core-promievent": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.7.0.tgz", - "integrity": "sha512-xPH66XeC0K0k29GoRd0vyPQ07yxERPRd4yVPrbMzGAz/e9E4M3XN//XK6+PdfGvGw3fx8VojS+tNIMiw+PujbQ==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-core-promievent/-/web3-core-promievent-1.7.3.tgz", + "integrity": "sha512-+mcfNJLP8h2JqcL/UdMGdRVfTdm+bsoLzAFtLpazE4u9kU7yJUgMMAqnK59fKD3Zpke3DjaUJKwz1TyiGM5wig==", "requires": { "eventemitter3": "4.0.4" }, @@ -46807,24 +46920,24 @@ } }, "web3-core-requestmanager": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.7.0.tgz", - "integrity": "sha512-rA3dBTBPrt+eIfTAQ2/oYNTN/2wbZaYNR3pFZGqG8+2oCK03+7oQyz4sWISKy/nYQhURh4GK01rs9sN4o/Tq9w==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-core-requestmanager/-/web3-core-requestmanager-1.7.3.tgz", + "integrity": "sha512-bC+jeOjPbagZi2IuL1J5d44f3zfPcgX+GWYUpE9vicNkPUxFBWRG+olhMo7L+BIcD57cTmukDlnz+1xBULAjFg==", "requires": { "util": "^0.12.0", - "web3-core-helpers": "1.7.0", - "web3-providers-http": "1.7.0", - "web3-providers-ipc": "1.7.0", - "web3-providers-ws": "1.7.0" + "web3-core-helpers": "1.7.3", + "web3-providers-http": "1.7.3", + "web3-providers-ipc": "1.7.3", + "web3-providers-ws": "1.7.3" } }, "web3-core-subscriptions": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.7.0.tgz", - "integrity": "sha512-6giF8pyJrPmWrRpc2WLoVCvQdMMADp20ZpAusEW72axauZCNlW1XfTjs0i4QHQBfdd2lFp65qad9IuATPhuzrQ==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-core-subscriptions/-/web3-core-subscriptions-1.7.3.tgz", + "integrity": "sha512-/i1ZCLW3SDxEs5mu7HW8KL4Vq7x4/fDXY+yf/vPoDljlpvcLEOnI8y9r7om+0kYwvuTlM6DUHHafvW0221TyRQ==", "requires": { "eventemitter3": "4.0.4", - "web3-core-helpers": "1.7.0" + "web3-core-helpers": "1.7.3" }, "dependencies": { "eventemitter3": { @@ -46835,37 +46948,37 @@ } }, "web3-eth": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.7.0.tgz", - "integrity": "sha512-3uYwjMjn/MZjKIzXCt4YL9ja/k9X5shfa4lKparZhZE6uesmu+xmSmrEFXA/e9qcveF50jkV7frjkT8H+cLYtw==", - "requires": { - "web3-core": "1.7.0", - "web3-core-helpers": "1.7.0", - "web3-core-method": "1.7.0", - "web3-core-subscriptions": "1.7.0", - "web3-eth-abi": "1.7.0", - "web3-eth-accounts": "1.7.0", - "web3-eth-contract": "1.7.0", - "web3-eth-ens": "1.7.0", - "web3-eth-iban": "1.7.0", - "web3-eth-personal": "1.7.0", - "web3-net": "1.7.0", - "web3-utils": "1.7.0" + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-eth/-/web3-eth-1.7.3.tgz", + "integrity": "sha512-BCIRMPwaMlTCbswXyGT6jj9chCh9RirbDFkPtvqozfQ73HGW7kP78TXXf9+Xdo1GjutQfxi/fQ9yPdxtDJEpDA==", + "requires": { + "web3-core": "1.7.3", + "web3-core-helpers": "1.7.3", + "web3-core-method": "1.7.3", + "web3-core-subscriptions": "1.7.3", + "web3-eth-abi": "1.7.3", + "web3-eth-accounts": "1.7.3", + "web3-eth-contract": "1.7.3", + "web3-eth-ens": "1.7.3", + "web3-eth-iban": "1.7.3", + "web3-eth-personal": "1.7.3", + "web3-net": "1.7.3", + "web3-utils": "1.7.3" } }, "web3-eth-abi": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.7.0.tgz", - "integrity": "sha512-heqR0bWxgCJwjWIhq2sGyNj9bwun5+Xox/LdZKe+WMyTSy0cXDXEAgv3XKNkXC4JqdDt/ZlbTEx4TWak4TRMSg==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.7.3.tgz", + "integrity": "sha512-ZlD8DrJro0ocnbZViZpAoMX44x5aYAb73u2tMq557rMmpiluZNnhcCYF/NnVMy6UIkn7SF/qEA45GXA1ne6Tnw==", "requires": { "@ethersproject/abi": "5.0.7", - "web3-utils": "1.7.0" + "web3-utils": "1.7.3" } }, "web3-eth-accounts": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.7.0.tgz", - "integrity": "sha512-Zwm7TlQXdXGRuS6+ib1YsR5fQwpfnFyL6UAZg1zERdrUrs3IkCZSL3yCP/8ZYbAjdTEwWljoott2iSqXNH09ug==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-eth-accounts/-/web3-eth-accounts-1.7.3.tgz", + "integrity": "sha512-aDaWjW1oJeh0LeSGRVyEBiTe/UD2/cMY4dD6pQYa8dOhwgMtNQjxIQ7kacBBXe7ZKhjbIFZDhvXN4mjXZ82R2Q==", "requires": { "@ethereumjs/common": "^2.5.0", "@ethereumjs/tx": "^3.3.2", @@ -46874,10 +46987,10 @@ "ethereumjs-util": "^7.0.10", "scrypt-js": "^3.0.1", "uuid": "3.3.2", - "web3-core": "1.7.0", - "web3-core-helpers": "1.7.0", - "web3-core-method": "1.7.0", - "web3-utils": "1.7.0" + "web3-core": "1.7.3", + "web3-core-helpers": "1.7.3", + "web3-core-method": "1.7.3", + "web3-utils": "1.7.3" }, "dependencies": { "eth-lib": { @@ -46898,99 +47011,99 @@ } }, "web3-eth-contract": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.7.0.tgz", - "integrity": "sha512-2LY1Xwxu5rx468nqHuhvupQAIpytxIUj3mGL9uexszkhrQf05THVe3i4OnUCzkeN6B2cDztNOqLT3j9SSnVQDg==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-eth-contract/-/web3-eth-contract-1.7.3.tgz", + "integrity": "sha512-7mjkLxCNMWlQrlfM/MmNnlKRHwFk5XrZcbndoMt3KejcqDP6dPHi2PZLutEcw07n/Sk8OMpSamyF3QiGfmyRxw==", "requires": { "@types/bn.js": "^4.11.5", - "web3-core": "1.7.0", - "web3-core-helpers": "1.7.0", - "web3-core-method": "1.7.0", - "web3-core-promievent": "1.7.0", - "web3-core-subscriptions": "1.7.0", - "web3-eth-abi": "1.7.0", - "web3-utils": "1.7.0" + "web3-core": "1.7.3", + "web3-core-helpers": "1.7.3", + "web3-core-method": "1.7.3", + "web3-core-promievent": "1.7.3", + "web3-core-subscriptions": "1.7.3", + "web3-eth-abi": "1.7.3", + "web3-utils": "1.7.3" } }, "web3-eth-ens": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.7.0.tgz", - "integrity": "sha512-I1bikYJJWQ/FJZIAvwsGOvzAgcRIkosWG4s1L6veRoXaU8OEJFeh4s00KcfHDxg7GWZZGbUSbdbzKpwRbWnvkg==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-eth-ens/-/web3-eth-ens-1.7.3.tgz", + "integrity": "sha512-q7+hFGHIc0mBI3LwgRVcLCQmp6GItsWgUtEZ5bjwdjOnJdbjYddm7PO9RDcTDQ6LIr7hqYaY4WTRnDHZ6BEt5Q==", "requires": { "content-hash": "^2.5.2", "eth-ens-namehash": "2.0.8", - "web3-core": "1.7.0", - "web3-core-helpers": "1.7.0", - "web3-core-promievent": "1.7.0", - "web3-eth-abi": "1.7.0", - "web3-eth-contract": "1.7.0", - "web3-utils": "1.7.0" + "web3-core": "1.7.3", + "web3-core-helpers": "1.7.3", + "web3-core-promievent": "1.7.3", + "web3-eth-abi": "1.7.3", + "web3-eth-contract": "1.7.3", + "web3-utils": "1.7.3" } }, "web3-eth-iban": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.7.0.tgz", - "integrity": "sha512-1PFE/Og+sPZaug+M9TqVUtjOtq0HecE+SjDcsOOysXSzslNC2CItBGkcRwbvUcS+LbIkA7MFsuqYxOL0IV/gyA==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-eth-iban/-/web3-eth-iban-1.7.3.tgz", + "integrity": "sha512-1GPVWgajwhh7g53mmYDD1YxcftQniIixMiRfOqlnA1w0mFGrTbCoPeVaSQ3XtSf+rYehNJIZAUeDBnONVjXXmg==", "requires": { "bn.js": "^4.11.9", - "web3-utils": "1.7.0" + "web3-utils": "1.7.3" } }, "web3-eth-personal": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.7.0.tgz", - "integrity": "sha512-Dr9RZTNOR80PhrPKGdktDUXpOgExEcCcosBj080lKCJFU1paSPj9Zfnth3u6BtIOXyKsVFTrpqekqUDyAwXnNw==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-eth-personal/-/web3-eth-personal-1.7.3.tgz", + "integrity": "sha512-iTLz2OYzEsJj2qGE4iXC1Gw+KZN924fTAl0ESBFs2VmRhvVaM7GFqZz/wx7/XESl3GVxGxlRje3gNK0oGIoYYQ==", "requires": { "@types/node": "^12.12.6", - "web3-core": "1.7.0", - "web3-core-helpers": "1.7.0", - "web3-core-method": "1.7.0", - "web3-net": "1.7.0", - "web3-utils": "1.7.0" + "web3-core": "1.7.3", + "web3-core-helpers": "1.7.3", + "web3-core-method": "1.7.3", + "web3-net": "1.7.3", + "web3-utils": "1.7.3" }, "dependencies": { "@types/node": { - "version": "12.20.46", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.46.tgz", - "integrity": "sha512-cPjLXj8d6anFPzFvOPxS3fvly3Shm5nTfl6g8X5smexixbuGUf7hfr21J5tX9JW+UPStp/5P5R8qrKL5IyVJ+A==" + "version": "12.20.50", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.50.tgz", + "integrity": "sha512-+9axpWx2b2JCVovr7Ilgt96uc6C1zBKOQMpGtRbWT9IoR/8ue32GGMfGA4woP8QyP2gBs6GQWEVM3tCybGCxDA==" } } }, "web3-net": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.7.0.tgz", - "integrity": "sha512-8pmfU1Se7DmG40Pu8nOCKlhuI12VsVzCtdFDnLAai0zGVAOUuuOCK71B2aKm6u9amWBJjtOlyrCwvsG+QEd6dw==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-net/-/web3-net-1.7.3.tgz", + "integrity": "sha512-zAByK0Qrr71k9XW0Adtn+EOuhS9bt77vhBO6epAeQ2/VKl8rCGLAwrl3GbeEl7kWa8s/su72cjI5OetG7cYR0g==", "requires": { - "web3-core": "1.7.0", - "web3-core-method": "1.7.0", - "web3-utils": "1.7.0" + "web3-core": "1.7.3", + "web3-core-method": "1.7.3", + "web3-utils": "1.7.3" } }, "web3-providers-http": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.7.0.tgz", - "integrity": "sha512-Y9reeEiApfvQKLUUtrU4Z0c+H6b7BMWcsxjgoXndI1C5NB297mIUfltXxfXsh5C/jk5qn4Q3sJp3SwQTyVjH7Q==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-providers-http/-/web3-providers-http-1.7.3.tgz", + "integrity": "sha512-TQJfMsDQ5Uq9zGMYlu7azx1L7EvxW+Llks3MaWn3cazzr5tnrDbGh6V17x6LN4t8tFDHWx0rYKr3mDPqyTjOZw==", "requires": { - "web3-core-helpers": "1.7.0", + "web3-core-helpers": "1.7.3", "xhr2-cookies": "1.1.0" } }, "web3-providers-ipc": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.7.0.tgz", - "integrity": "sha512-U5YLXgu6fvAK4nnMYqo9eoml3WywgTym0dgCdVX/n1UegLIQ4nctTubBAuWQEJzmAzwh+a6ValGcE7ZApTRI7Q==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-providers-ipc/-/web3-providers-ipc-1.7.3.tgz", + "integrity": "sha512-Z4EGdLKzz6I1Bw+VcSyqVN4EJiT2uAro48Am1eRvxUi4vktGoZtge1ixiyfrRIVb6nPe7KnTFl30eQBtMqS0zA==", "requires": { "oboe": "2.1.5", - "web3-core-helpers": "1.7.0" + "web3-core-helpers": "1.7.3" } }, "web3-providers-ws": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.7.0.tgz", - "integrity": "sha512-0a8+lVV3JBf+eYnGOsdzOpftK1kis5X7s35QAdoaG5SDapnEylXFlR4xDSSSU88ZwMwvse8hvng2xW6A7oeWxw==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-providers-ws/-/web3-providers-ws-1.7.3.tgz", + "integrity": "sha512-PpykGbkkkKtxPgv7U4ny4UhnkqSZDfLgBEvFTXuXLAngbX/qdgfYkhIuz3MiGplfL7Yh93SQw3xDjImXmn2Rgw==", "requires": { "eventemitter3": "4.0.4", - "web3-core-helpers": "1.7.0", + "web3-core-helpers": "1.7.3", "websocket": "^1.0.32" }, "dependencies": { @@ -47002,20 +47115,20 @@ } }, "web3-shh": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.7.0.tgz", - "integrity": "sha512-RZhxcevALIPK178VZCpwMBvQeW+IoWtRJ4EMdegpbnETeZaC3aRUcs6vKnrf0jXJjm4J/E2Dt438Y1Ord/1IMw==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-shh/-/web3-shh-1.7.3.tgz", + "integrity": "sha512-bQTSKkyG7GkuULdZInJ0osHjnmkHij9tAySibpev1XjYdjLiQnd0J9YGF4HjvxoG3glNROpuCyTaRLrsLwaZuw==", "requires": { - "web3-core": "1.7.0", - "web3-core-method": "1.7.0", - "web3-core-subscriptions": "1.7.0", - "web3-net": "1.7.0" + "web3-core": "1.7.3", + "web3-core-method": "1.7.3", + "web3-core-subscriptions": "1.7.3", + "web3-net": "1.7.3" } }, "web3-utils": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.7.0.tgz", - "integrity": "sha512-O8Tl4Ky40Sp6pe89Olk2FsaUkgHyb5QAXuaKo38ms3CxZZ4d3rPGfjP9DNKGm5+IUgAZBNpF1VmlSmNCqfDI1w==", + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.7.3.tgz", + "integrity": "sha512-g6nQgvb/bUpVUIxJE+ezVN+rYwYmlFyMvMIRSuqpi1dk6ApDD00YNArrk7sPcZnjvxOJ76813Xs2vIN2rgh4lg==", "requires": { "bn.js": "^4.11.9", "ethereum-bloom-filters": "^1.0.6", @@ -47450,9 +47563,9 @@ }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==" }, "strip-ansi": { "version": "5.2.0", @@ -47684,9 +47797,9 @@ }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==" }, "strip-ansi": { "version": "5.2.0", @@ -47734,9 +47847,9 @@ }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==" }, "strip-ansi": { "version": "5.2.0", @@ -48067,11 +48180,6 @@ "graceful-fs": "^4.1.6" } }, - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" - }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", @@ -48455,4 +48563,4 @@ } } } -} \ No newline at end of file +} diff --git a/web-installer/package.json b/web-installer/package.json index 1d4f0f4c4..07f28daf3 100644 --- a/web-installer/package.json +++ b/web-installer/package.json @@ -1,6 +1,6 @@ { "name": "webinstaller", - "version": "1.1.0", + "version": "1.1.1", "private": true, "dependencies": { "@material-ui/core": "^4.11.0", diff --git a/web-installer/src/redux/reducers/chainlinkChainsReducer.js b/web-installer/src/redux/reducers/chainlinkChainsReducer.js index 5c99be410..df617671c 100644 --- a/web-installer/src/redux/reducers/chainlinkChainsReducer.js +++ b/web-installer/src/redux/reducers/chainlinkChainsReducer.js @@ -175,12 +175,12 @@ const chainlinkThresholdAlerts = { enabled: true, }, 8: { - name: 'Chainlink node: ETH Balance', - identifier: 'eth_balance_amount', + name: 'Chainlink node: Account Balance', + identifier: 'balance_amount', description: - 'If the amount of ETH is less than the threshold an alert ' + 'If the account balance is less than the threshold an alert ' + 'will be raised. This applies to all EVM networks e.g BNB.', - adornment: 'ETH Balance', + adornment: 'Balance', adornment_time: 'Seconds', parent_id: '', warning: { @@ -413,9 +413,9 @@ const chainlinkSeverityAlerts = { enabled: true, }, 19: { - name: 'Ethereum Balance Topped Up', - identifier: 'eth_balance_amount_increase', - description: 'Whenever the ethereum balance of a node is topped up you will get alerted.', + name: 'Account Balance Topped Up', + identifier: 'balance_amount_increase', + description: 'Whenever the account balance of a node is topped up you will get alerted.', severity: INFO, parent_id: '', enabled: true,