Merge pull request #1601 from apache/dependabot/maven/services/billing-aws/com.amazonaws-aws-java-sdk-s3-1.12.261

Bump aws-java-sdk-s3 from 1.11.48 to 1.12.261 in /services/billing-aws
diff --git a/NOTICE b/NOTICE
index 26ff06d..ee23e35 100644
--- a/NOTICE
+++ b/NOTICE
@@ -1,5 +1,5 @@
 Apache DataLab (incubating)
-Copyright 2018-2021 The Apache Software Foundation
+Copyright 2018-2022 The Apache Software Foundation
 
 This product includes software developed at
 The Apache Software Foundation (http://www.apache.org/).
diff --git a/README.md b/README.md
index f8b5596..1453dae 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,8 @@
 
         [Self-Service Node](#Self_Service_Node)
 
+        [Endpoint Node](#Endpoint_node)
+
         [Edge Node](#Edge_Node)
 
         [Notebook node](#Notebook_node)
@@ -815,6 +817,356 @@
 pre-defined VPC and Subnet.
 </details>
 
+## Endpoint node <a name="Endpoint_node"></a>
+
+This node allows you to create Edge nodes and Notebooks on other cloud providers (AWS, Microsoft Azure or GCP).
+The exception is the option in which Edge nodes and Notebooks are created on the same cloud provider as Self-Service Node,
+in which case endpoint is already provided locally.
+
+
+### Executing deployment script
+
+<details><summary>In Amazon <i>(click to expand)</i></summary>
+
+```
+source /venv/bin/activate
+/venv/bin/python3 infrastructure-provisioning/terraform/bin/datalab.py deploy aws endpoint \
+--access_key_id access_key \
+--secret_access_key secret_access_key \
+--key_name datalab-key \
+--pkey /path/to/private/key.pem \
+--path_to_pub_key /path/key.pub \
+--service_base_name datalab-test \
+--endpoint_id awstest \
+--region xx-xxx \
+--zone xxxx \
+--cloud_provider aws \
+--vpc_id xxxxxxx \
+--subnet_id xxxxxxx \
+--ssn_ui_host 0.0.0.0 \
+--billing_enable true/false \
+--billing_bucket xxxxxxx \
+--report_path xxxxxxxxx \
+--billing_aws_account_id xxxxxxxxx \
+--billing_tag xxxxxxx \
+--mongo_password xxxxxxxxxx
+deactivate
+```
+
+The following AWS resources will be created:
+- Endpoint EC2 instance
+- Elastic IP address for Endpoint EC2 instance
+- S3 bucket
+- Security Group for Endpoint instance
+- IAM Roles and Instance Profiles for Endpoint instance
+- User private subnet. All further nodes (Notebooks, EMR clusters) will be provisioned in different subnet than SSN.
+
+List of parameters for Endpoint deployment:
+
+| Parameter                  | Description/Value                                                                                                                           |
+|----------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
+| service\_base\_name        | Any infrastructure value (should be unique if multiple SSN’s have been deployed before)                                                     |                           
+| pkey                       | Path to private key                                                                                                                         |
+| path\_to\_pub\_key         | Path to public key                                                                                                                          |
+| key\_name                  | Name of the uploaded SSH key file (without “.pem” extension)                                                                                |
+| endpoint\_id               | ID of the endpoint                                                                                                                          |
+| cloud\_provider            | Name of the cloud provider, which is supported by DataLab (AWS)                                                                             |
+| access\_key\_id            | AWS user access key                                                                                                                         |
+| secret\_access\_key        | AWS user secret access key                                                                                                                  |
+| region                     | AWS region                                                                                                                                  |
+| vpc\_id                    | ID of the VPC (optional)                                                                                                                    |
+| ssn\_ui\_host              | IP address of SSN host on the cloud provider                                                                                                |
+| subnet\_id                 | ID of the public subnet (optional)                                                                                                          |
+| billing\_enable            | Enabling or disabling billing                                                                                                               |
+| billing\_bucket            | The name of S3 bucket where billing reports will be placed                                                                                  |
+| report\_path               | The path to billing reports directory in S3 bucket. This parameter isn't required when billing reports are placed in the root of S3 bucket. |
+| mongo\_password            | Mongo database password                                                                                                                     |                                                                                                                                            
+
+</details>
+
+<details><summary>In Azure <i>(click to expand)</i></summary>
+
+```
+source /venv/bin/activate
+/venv/bin/python3 infrastructure-provisioning/terraform/bin/datalab.py deploy azure endpoint \
+--auth_file_path /path/to/auth.json
+--key_name datalab-key \
+--pkey /path/to/private/key.pem \
+--path_to_pub_key /path/key.pub \
+--service_base_name datalab-test \
+--resource_group_name datalab-test-group \
+--endpoint_id azuretest \
+--region xx-xxx \
+--zone xxxx \
+--cloud_provider azure \
+--vpc_id xxxxxxx \
+--subnet_id xxxxxxx \
+--ssn_ui_host 0.0.0.0 \
+--billing_enable true/false \
+--billing_bucket xxxxxxx \
+--report_path xxxxxxxxx \
+--billing_aws_account_id xxxxxxxxx \
+--billing_tag xxxxxxx \
+--mongo_password xxxxxxxxxx \
+--offer_number xxxxxxxx \
+--currency "USD"  \
+--locale "en-US" \
+--region_info "US"
+deactivate
+```
+
+The following Azure resources will be created:
+-   Endpoint virtual machine
+-   Static public IP address for Endpoint virtual machine
+-   Network interface for Endpoint node
+-   Security Group for user's Endpoint instance
+-   Endpoint's private subnet.
+
+List of parameters for Endpoint deployment:
+
+| Parameter             | Description/Value                                                                       |
+|-----------------------|-----------------------------------------------------------------------------------------|
+| service\_base\_name   | Any infrastructure value (should be unique if multiple SSN’s have been deployed before) |
+| pkey                  | Path to private key                                                                     |
+| path\_to\_pub\_key    | Path to public key                                                                      |
+| key\_name             | Name of the uploaded SSH key file (without “.pem” extension)                            |
+| endpoint\_id          | ID of the endpoint                                                                      |
+| cloud\_provider       | Name of the cloud provider, which is supported by DataLab (Azure)                       |
+| vpc\_id               | Name of the Virtual Network (VN) (optional)                                             |
+| subnet\_id            | Name of the Azure subnet (optional)                                                     |
+| ssn\_ui\_host         | IP address of SSN host on the cloud provider                                            |
+| resource\_group\_name | Resource group name (can be the same as service base name                               |
+| region                | Azure region                                                                            |
+| auth\_file\_path      | Full path to auth json file                                                             |
+| offer\_number         | Azure offer id number                                                                   |
+| currency              | Currency that is used for billing information(e.g. USD)                                 |
+| locale                | Locale that is used for billing information(e.g. en-US)                                 |
+| region\_info          | Region info that is used for billing information(e.g. US)                               |
+| billing\_enable       | Enabling or disabling billing                                                           |
+| mongo\_password       | Mongo database password                                                                 |                                                                                                                                            
+
+</details>
+
+<details><summary>In Google cloud <i>(click to expand)</i></summary>
+
+```
+source /venv/bin/activate
+/venv/bin/python3 infrastructure-provisioning/terraform/bin/datalab.py deploy gcp endpoint \
+--gcp_project_id xxx-xxxx-xxxxxx \
+--creds_file /path/to/auth.json \
+--key_name datalab-key \
+--pkey /path/to/private/key.pem \
+--service_base_name datalab-test \
+--path_to_pub_key /path/key.pub \
+--endpoint_id gcptest \
+--region xx-xxx \
+--zone xxxx \
+--cloud_provider gcp \
+--vpc_id xxxxxxx \
+--subnet_id xxxxxxx \
+--ssn_ui_host 0.0.0.0 \
+--mongo_password xxxxxxxxxx \
+--billing_dataset_name xxxxxxxx \
+--billing_enable true/false
+deactivate
+```
+
+The following GCP resources will be created:
+- Endpoint VM instance
+- External static IP address for Endpoint VM instance
+- Security Group for Endpoint instance
+- Endpoint's private subnet.
+
+List of parameters for Endpoint deployment:
+
+| Parameter              | Description/Value                                                                       |
+|------------------------|-----------------------------------------------------------------------------------------|
+| service\_base\_name    | Any infrastructure value (should be unique if multiple SSN’s have been deployed before) |
+| pkey                   | Path to private key                                                                     |
+| path\_to\_pub\_key     | Path to public key                                                                      |
+| key\_name              | Name of the uploaded SSH key file (without “.pem” extension)                            |
+| endpoint\_id           | ID of the endpoint                                                                      |
+| cloud\_provider        | Name of the cloud provider, which is supported by DataLab (GCP)                         |
+| creds\_file            | Full path to auth json file                                                             |
+| gcp\_project\_id       | ID of GCP project                                                                       |
+| region                 | GCP region                                                                              |
+| zone                   | GCP zone                                                                                |
+| vpc\_id                | Name of the Virtual Network (VN) (optional)                                             |
+| subnet\_id             | Name of the GCP subnet (optional)                                                       |
+| billing\_dataset\_name | Name of GCP dataset (BigQuery service)                                                  |
+| ssn\_ui\_host          | IP address of SSN host on the cloud provider                                            |
+| billing\_enable        | Enabling or disabling billing                                                           |
+| mongo\_password        | Mongo database password                                                                 |                                                                                                                                            
+
+
+</details>
+
+### Terminating Endpoint
+
+<details><summary>In Amazon <i>(click to expand)</i></summary>
+
+```
+source /venv/bin/activate
+/venv/bin/python3 infrastructure-provisioning/terraform/bin/datalab.py destroy aws endpoint \
+--access_key_id access_key \
+--secret_access_key secret_access_key \
+--key_name datalab-key \
+--pkey /path/to/private/key.pem \
+--path_to_pub_key /path/key.pub \
+--service_base_name datalab-test \
+--endpoint_id awstest \
+--region xx-xxx \
+--zone xxxx \
+--cloud_provider aws \
+--vpc_id xxxxxxx \
+--subnet_id xxxxxxx \
+--ssn_ui_host 0.0.0.0 \
+--billing_enable true/false \
+--billing_bucket xxxxxxx \
+--report_path xxxxxxxxx \
+--billing_aws_account_id xxxxxxxxx \
+--billing_tag xxxxxxx \
+--mongo_password xxxxxxxxxx
+deactivate
+```
+
+
+List of parameters for Endpoint termination:
+
+| Parameter                  | Description/Value                                                                                                                           |
+|----------------------------|---------------------------------------------------------------------------------------------------------------------------------------------|
+| service\_base\_name        | Any infrastructure value (should be unique if multiple SSN’s have been deployed before)                                                     |                           
+| pkey                       | Path to private key                                                                                                                         |
+| path\_to\_pub\_key         | Path to public key                                                                                                                          |
+| key\_name                  | Name of the uploaded SSH key file (without “.pem” extension)                                                                                |
+| endpoint\_id               | ID of the endpoint                                                                                                                          |
+| cloud\_provider            | Name of the cloud provider, which is supported by DataLab (AWS)                                                                             |
+| access\_key\_id            | AWS user access key                                                                                                                         |
+| secret\_access\_key        | AWS user secret access key                                                                                                                  |
+| region                     | AWS region                                                                                                                                  |
+| vpc\_id                    | ID of the VPC (optional)                                                                                                                    |
+| ssn\_ui\_host              | IP address of SSN host on the cloud provider                                                                                                |
+| subnet\_id                 | ID of the public subnet (optional)                                                                                                          |
+| billing\_enable            | Enabling or disabling billing                                                                                                               |
+| billing\_bucket            | The name of S3 bucket where billing reports will be placed                                                                                  |
+| report\_path               | The path to billing reports directory in S3 bucket. This parameter isn't required when billing reports are placed in the root of S3 bucket. |
+| mongo\_password            | Mongo database password                                                                                                                     |                                                                                                                                            
+
+
+</details>
+
+<details><summary>In Azure <i>(click to expand)</i></summary>
+
+```
+source /venv/bin/activate
+/venv/bin/python3 infrastructure-provisioning/terraform/bin/datalab.py destroy azure endpoint \
+--auth_file_path /path/to/auth.json
+--key_name datalab-key \
+--pkey /path/to/private/key.pem \
+--path_to_pub_key /path/key.pub \
+--service_base_name datalab-test \
+--resource_group_name datalab-test-group \
+--endpoint_id azuretest \
+--region xx-xxx \
+--zone xxxx \
+--cloud_provider azure \
+--vpc_id xxxxxxx \
+--subnet_id xxxxxxx \
+--ssn_ui_host 0.0.0.0 \
+--billing_enable true/false \
+--billing_bucket xxxxxxx \
+--report_path xxxxxxxxx \
+--billing_aws_account_id xxxxxxxxx \
+--billing_tag xxxxxxx \
+--mongo_password xxxxxxxxxx \
+--offer_number xxxxxxxx \
+--currency "USD"  \
+--locale "en-US" \
+--region_info "US"
+deactivate
+```
+
+
+List of parameters for Endpoint termination:
+
+| Parameter             | Description/Value                                                                       |
+|-----------------------|-----------------------------------------------------------------------------------------|
+| service\_base\_name   | Any infrastructure value (should be unique if multiple SSN’s have been deployed before) |
+| pkey                  | Path to private key                                                                     |
+| path\_to\_pub\_key    | Path to public key                                                                      |
+| key\_name             | Name of the uploaded SSH key file (without “.pem” extension)                            |
+| endpoint\_id          | ID of the endpoint                                                                      |
+| cloud\_provider       | Name of the cloud provider, which is supported by DataLab (Azure)                       |
+| vpc\_id               | Name of the Virtual Network (VN) (optional)                                             |
+| subnet\_id            | Name of the Azure subnet (optional)                                                     |
+| ssn\_ui\_host         | IP address of SSN host on the cloud provider                                            |
+| resource\_group\_name | Resource group name (can be the same as service base name                               |
+| region                | Azure region                                                                            |
+| auth\_file\_path      | Full path to auth json file                                                             |
+| offer\_number         | Azure offer id number                                                                   |
+| currency              | Currency that is used for billing information(e.g. USD)                                 |
+| locale                | Locale that is used for billing information(e.g. en-US)                                 |
+| region\_info          | Region info that is used for billing information(e.g. US)                               |
+| billing\_enable       | Enabling or disabling billing                                                           |
+| mongo\_password       | Mongo database password                                                                 |                                                                                                                                            
+
+
+</details>
+
+<details><summary>In Google cloud <i>(click to expand)</i></summary>
+
+```
+source /venv/bin/activate
+/venv/bin/python3 infrastructure-provisioning/terraform/bin/datalab.py destroy gcp endpoint \
+--gcp_project_id xxx-xxxx-xxxxxx \
+--creds_file /path/to/auth.json \
+--key_name datalab-key \
+--pkey /path/to/private/key.pem \
+--service_base_name datalab-test \
+--path_to_pub_key /path/key.pub \
+--endpoint_id gcptest \
+--region xx-xxx \
+--zone xxxx \
+--cloud_provider gcp \
+--vpc_id xxxxxxx \
+--subnet_id xxxxxxx \
+--ssn_ui_host 0.0.0.0 \
+--mongo_password xxxxxxxxxx \
+--billing_dataset_name xxxxxxxx \
+--billing_enable true/false
+deactivate
+```
+
+List of parameters for Endpoint termination:
+
+| Parameter              | Description/Value                                                                       |
+|------------------------|-----------------------------------------------------------------------------------------|
+| service\_base\_name    | Any infrastructure value (should be unique if multiple SSN’s have been deployed before) |
+| pkey                   | Path to private key                                                                     |
+| path\_to\_pub\_key     | Path to public key                                                                      |
+| key\_name              | Name of the uploaded SSH key file (without “.pem” extension)                            |
+| endpoint\_id           | ID of the endpoint                                                                      |
+| cloud\_provider        | Name of the cloud provider, which is supported by DataLab (GCP)                         |
+| creds\_file            | Full path to auth json file                                                             |
+| gcp\_project\_id       | ID of GCP project                                                                       |
+| region                 | GCP region                                                                              |
+| zone                   | GCP zone                                                                                |
+| vpc\_id                | Name of the Virtual Network (VN) (optional)                                             |
+| subnet\_id             | Name of the GCP subnet (optional)                                                       |
+| billing\_dataset\_name | Name of GCP dataset (BigQuery service)                                                  |
+| ssn\_ui\_host          | IP address of SSN host on the cloud provider                                            |
+| billing\_enable        | Enabling or disabling billing                                                           |
+| mongo\_password        | Mongo database password                                                                 |                                                                                                                                            
+
+
+</details>
+
+After creating endpoint, you must set the endpoint in Datalab UI. To do this, go to the tab
+"Resources" - "Endpoints". In the Name field, you should specify the name of the endpoint, in the URL, 
+specify the network address of the endpoint (taking as an example https://0.0.0.0:8084/). In the Account field, you need to 
+specify the "endpoint_id" value that was specified when creating the endpoint (for example, awstest, azuretest or gcptest), 
+in the Endpoint tag field, specify the endpoint tag (optional).
+
 ## Edge Node <a name="Edge_Node"></a>
 
 Gateway node (or an Edge node) is an instance(virtual machine) provisioned in a public subnet. It serves as an entry 
@@ -2162,6 +2514,7 @@
 
   * Download MongoDB from [https://www.mongodb.com/download-center](https://www.mongodb.com/download-center)
   * Install database based on MongoDB instructions
+  * Download and install MongoDB Database Tools [https://www.mongodb.com/try/download/database-tools](https://www.mongodb.com/try/download/database-tools)
   * Start DB server and create accounts
 ```
 use admin
@@ -2190,7 +2543,7 @@
 mongoimport -u admin -p <password> -d <database_name> -c settings mongo_settings.json
 ```
 
-  * Load collections form file datalab/infrastructure-provisioning/src/ssn/files/mongo_roles.json
+  * Load collections form file datalab/infrastructure-provisioning/src/ssn/files/(aws|azure)/mongo_roles.json
 
 ```
 mongoimport -u admin -p <password> -d <database_name> --jsonArray -c roles mongo_roles.json
@@ -2236,7 +2589,7 @@
 
 ### Install Node.js
 
-  * Download Node.js from [https://nodejs.org/en](https://nodejs.org/en)
+  * Download Node.js LTS from [https://nodejs.org/en](https://nodejs.org/en)
   * Install Node.js
   * Make sure that the installation folder of Node.js has been added  to the system environment variable **PATH**
   * Install latest packages
@@ -2252,13 +2605,7 @@
 ```
 npm install
 ```
-  * Replace CLOUD_PROVIDER options with aws|azure in dictionary file<br> datalab/services/self-service/src/main/resources/webapp/src/dictionary/global.dictionary.ts
 
-```
-import { NAMING_CONVENTION } from './(aws|azure).dictionary';
-
-export * from './(aws|azure).dictionary';
-```
   * Build web application
 
 ```
@@ -2283,7 +2630,7 @@
 
 #### Create Unix/Ubuntu server certificate
 
-Pay attention that the last command has to be executed with administrative permissions.
+Pay attention that the last command has to be executed with administrative permissions. Use keytool bundled with JRE. 
 ```
 keytool -genkeypair -alias ssn -keyalg RSA -storepass KEYSTORE_PASSWORD -keypass KEYSTORE_PASSWORD -keystore ~/keys/ssn.keystore.jks -keysize 2048 -dname "CN=localhost"
 keytool -exportcert -alias ssn -storepass KEYSTORE_PASSWORD -file ~/keys/ssn.crt -keystore ~/keys/ssn.keystore.jks
@@ -2292,7 +2639,7 @@
 #### Create Windows server certificate
 
 Pay attention that the last command has to be executed with administrative permissions.
-To achieve this the command line (cmd) should be ran with administrative permissions.  
+To achieve this the command line (cmd) should be ran with administrative permissions. Path to <DRIVE_LETTER>:\home\%USERNAME%\keys should exist.  
 ```
 "%JRE_HOME%\bin\keytool" -genkeypair -alias ssn -keyalg RSA -storepass KEYSTORE_PASSWORD -keypass KEYSTORE_PASSWORD -keystore <DRIVE_LETTER>:\home\%USERNAME%\keys\ssn.keystore.jks -keysize 2048 -dname "CN=localhost"
 "%JRE_HOME%\bin\keytool" -exportcert -alias ssn -storepass KEYSTORE_PASSWORD -file <DRIVE_LETTER>:\home\%USERNAME%\keys\ssn.crt -keystore <DRIVE_LETTER>:\home\%USERNAME%\keys\ssn.keystore.jks
@@ -2310,7 +2657,7 @@
  Open infrastructure-provisioning/src/ssn/templates/ssn.yml 
  
  * (23) KEYS_DIR -> path to keys dir with backslash
- * (30) CLOUD_TYPE -> CLOUD_PROVIDER to gcp
+ * (30) CLOUD_TYPE -> CLOUD_PROVIDER to aws
  * (34) DEV_MODE -> false to true
  * (40-42) change user, pass, db to created in prev step
  
@@ -2364,7 +2711,7 @@
     * Create Application with name provisining-service-application
         * Main class: 
         ``` com.epam.datalab.backendapi.ProvisioningServiceApplication```
-        * VM options:  ```-Ddocker.dir=[PATH_TO_PROJECT_DIR]\infrastructure-provisioning\src\general\files\gcp```
+        * VM options:  ```-Ddocker.dir=[PATH_TO_PROJECT_DIR]\infrastructure-provisioning\src\general\files\aws```
         * Program arguments : ```server
                               [PATH_TO_PROJECT_DIR]\services\provisioning-service\provisioning.yml```
         * Working directory:```[PATH_TO_PROJECT_DIR]```
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 8ec41ab..c9d370a 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,41 +1,72 @@
 # DataLab is Self-service, Fail-safe Exploratory Environment for Collaborative Data Science Workflow
 
-## Improvements in v2.5.1
+## New features in v2.6.0
+
 **All cloud platforms:**
-- Added GPU filter type and count for easier environment management by administrator;
-- Added explanation for open terminal action on Audit page.
+- Implemented Images page, where DataLab users may view and manage custom images. 
+  * Now DataLab user can: 
+    - View the list of own and shared custom images; 
+    - View additional info about custom image; 
+    - View activities on sharing/stopping sharing custom images; 
+    - Share custom images with selected users or user groups; 
+    - Stop sharing custom images with selected users or user groups; 
+    - Terminate custom images. 
+  * DataLab administrators can grant permission to user for: 
+    - Sharing own custom images; 
+    - Terminating own custom images; 
+    - Notebook creation based on own custom images; 
+    - Notebook creation based on shared custom images.
+- Updated versions of installed software:
+  * Jupyter notebook v.6.4.12;
+  * JupyterLab notebook v.3.4.3;
+  * Superset notebook v.1.5.1;
+  * TensorFlow notebook v.2.9.1;
+  * RStudio notebook v.2022.02.2-485;
+  * Angular v.11.2.14;
+  * Keycloak v.18.0.1.
+- Added the possibility to connect a new data platform to DataLab account.
+  * Now DataLab users can connect MLflow platform.
 
-## Bug fixes in v2.5.1
+**AWS:**
+- Added a new template JupyterLab with TensorFlow.
+
 **Azure:**
-- Fixed a bug when instance creation failed on stage of devtools installation;
-- Fixed a bug when Apache Zeppelin notebook creation failed during shell interpreter configuration;
-- Fixed a bug when edge node status on WEB DataLab UI was not synced up with Cloud instance status;
-- Fixed a bug when DeepLearning creation failed due to wrong path to connector;
-- Fixed a bug when not all billing drop down values were visible;
-- Fixed minor  UI issues which were reproduced only for smaller desktop size;
-- Fixed a bug when connection for Jupyter R/Scala kernels were unsuccessful;
-- Fixed a bug when Data Engine creation failed on Jupyter/RStudio/Apache Zeppelin notebooks;
-- Fixed a bug when very often notebook/Data Engine creation and stopping failed due to low level socket;
-- Fixed a bug when Jupyter/RStudio/DeepLearning notebooks creation failed from image;
-- Fixed a bug when SSN/any type of notebook creation was not always successful from the first attempt.
+- Added support of Data Engine Service (HDInsight) for RStudio, Jupyter & Apache Zeppelin notebooks.
 
-**Azure and GCP:**
-- Fixed a bug when time to time DeepLearning notebook creation failed on stage of nvidia installation;
-- Fixed a bug when sometimes any type of notebook creation failed during disk mount.
+## Improvements in v2.6.0
 
-## Known issues in v2.5.1
+**All cloud platforms:**
+- Added ability to start user's notebook from administrative panel;
+- Improved filter function by creating a separate “Filter” action button (in this release available only for Image page, to be updated on other pages in the next releases);
+- Added minor improvements for About & Help sections to make user experience easier and more intuitive.
+
+## Bug fixes in v2.6.0
+
+**All cloud platforms:**
+- Fixed a bug when project creation was allowed after total quota exceeded;
+- Fixed a bug when Ungit link leaded to 502 error for DeepLearning notebook;
+- Fixed wrong date & time data of uploaded objects in the bucket browser;
+- Fixed a bug when R package was absent for installation from DataLab WEB UI for RStudio & Apache Zeppelin notebooks;
+
+**AWS:**
+- Fixed a bug when EMR creation failed on RStudio & Apache Zeppelin notebooks.
+
 **GCP:**
-- Superset creation fails during configuration;
+- Fixed a bug when Superset creation failed during configuration;
+- Fixed a bug when  Dataproc creation failed on RStudio & Apache Zeppelin notebooks;
+- Fixed a bug when billing data were absent for Compute;
+- Fixed a bug when DataLab deployment was unsuccessful in existing VPC or subnet.
+
+## Known issues in v2.6.0
+
+**GCP:**
 - SSO is not available for Superset.
 
-**Microsoft Azure:**
-- Notebook WEB terminal does not work for remote endpoint.
+*Refer to the following link in order to view other major/minor issues in v2.6.0*
 
-*Refer to the following link in order to view other major/minor issues in v2.5.1*
+[Apache DataLab: Known issues](https://issues.apache.org/jira/issues/?filter=12352236)
 
-[Apache DataLab: Known issues](https://issues.apache.org/jira/issues/?filter=12351099 "Apache DataLab: Known issues")
-
-## Known issues caused by cloud provider limitations in v2.5.1
+## Known issues caused by cloud provider limitations in v2.6.0
 
 **Microsoft Azure:**
 - Resource name length should not exceed 80 chars.
diff --git a/USER_GUIDE.md b/USER_GUIDE.md
index 20b212b..6739bd7 100644
--- a/USER_GUIDE.md
+++ b/USER_GUIDE.md
@@ -46,7 +46,7 @@
 
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [Project management](#project_management)
 
-&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [Environment management](#environment_management)
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [Resourses](#environment_management)
 
 &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; [Multiple Cloud endpoints](#multiple_cloud_endpoints)
 
@@ -68,21 +68,24 @@
 
 DataLab Web Application authenticates users against:
 
--   OpenLdap;
--   Cloud Identity and Access Management service user validation;
--   KeyCloak integration for seamless SSO experience *;
+As soon as DataLab is deployed by an infrastructure provisioning team and you received DataLab URL, your username and password – open DataLab login page, fill in your credentials and hit Login.
+
+DataLab Web Application authenticates users against:
+
+-   KeyCloak integration for seamless SSO experience;
 
     * NOTE: in case has been installed and configured to use SSO, please click on "Login with SSO" and use your corporate credentials
 
 | Login error messages               | Reason                                                                           |
 |------------------------------------|----------------------------------------------------------------------------------|
-| Username or password is invalid |The username provided:<br>doesn’t match any LDAP user OR<br>there is a type in the password field |
-| Please contact AWS administrator to create corresponding IAM User | The user name provided:<br>exists in LDAP BUT:<br>doesn’t match any of IAM users in AWS |
-| Please contact AWS administrator to activate your Access Key      | The username provided:<br>exists in LDAP BUT:<br>IAM user doesn’t have a single Access Key\* created OR<br>IAM user’s Access Key is Inactive |
+| Invalid username or password. |The username provided: doesn’t match any LDAP user OR there is a type in the password field |
 
-\* Please refer to official documentation from Amazon to figure out how to manage Access Keys for your AWS Account: http://docs.aws.amazon.com/general/latest/gr/managing-aws-access-keys.html
 
-To stop working with DataLab - click on Log Out link at the top right corner of DataLab.
+To stop working with DataLab - click on user icon <img src="doc/user.png" alt="user" width="20"> at the top right corner of DataLab and hit "Log out from account" button:
+
+<p align="center" class="facebox-popup"> 
+    <img src="doc/user_information.png" alt="User information" width="300">
+</p>
 
 After login user sees warning in case of exceeding quota or close to this limit.
 
@@ -107,9 +110,9 @@
 
 Please note, that you need to have a key pair combination (public and private key) to work with DataLab. To figure out how to create public and private key, please click on “Where can I get public key?” on “Projects” page. DataLab build-in wiki page guides Windows, MasOS and Linux on how to generate SSH key pairs quickly.
 
-Creation of Project starts after hitting "Create" button. This process is a one-time operation for each Data Scientist and it might take up-to 10 minutes for DataLab to setup initial infrastructure for you. During this process project is in status "Creating".
+Creation of Project starts after hitting "Create" button. This process is a one-time operation for each Data Scientist and it might take up-to 25 minutes for DataLab to setup initial infrastructure for you. During this process project is in status "Creating".
 
-As soon as Project is created, Data Scientist can create  notebook server on “List of Resources” page. The message “To start working, please create new environment” is appeared on “List of Resources” page:
+As soon as Project is created, Data Scientist can create  notebook server in “Resources” section on "Instances" page . The message “To start working, please create new environment” is appeared on “Instances” page:
 
 ![Main page](doc/main_page.png)
 
@@ -119,7 +122,7 @@
 
 ## Create notebook server <a name="notebook_create"></a>
 
-To create new analytical environment from “List of Resources” page click on "Create new" button.
+To create new analytical environment from “Instances” page click on "Create new" button.
 
 The "Create analytical tool" popup shows up. Data Scientist can choose the preferred project, endpoint and analytical tool. Adding new analytical toolset is supported by architecture, so you can expect new templates to show up in upcoming releases.
 Currently by means of DataLab, Data Scientists can select between any of the following templates:
@@ -129,7 +132,7 @@
 -   RStudio
 -   RStudio with TensorFlow (implemented on AWS)
 -   Jupyter with TensorFlow
--   Deep Learning (Jupyter + MXNet, Caffe2, TensorFlow, CNTK, Theano, PyTorch and Keras)
+-   Deep Learning based on Cloud native image
 -   JupyterLab
 -   Superset (implemented on GCP)
 
@@ -139,7 +142,7 @@
 
 After specifying desired template, you should fill in the “Name” and “Instance shape”.
 
-Keep in mind that "Name" field – is just for visual differentiation between analytical tools on “List of resources” dashboard.
+Keep in mind that "Name" field – is just for visual differentiation between analytical tools on “Instances” dashboard.
 
 Instance shape dropdown, contains configurable list of shapes, which should be chosen depending on the type of analytical work to be performed. Following groups of instance shapes are showing up with default setup configuration:
 
@@ -189,6 +192,13 @@
 
 To access analytical tool Web UI you use direct URL's (your access is established via reverse proxy, so you don't need to have Edge node tunnel up and running).
 
+
+**TensorBoard usage**
+
+Tensorboard, the one that can be accessed by the URL from DataLab UI uses --logdir=/var/log/tensorboard.
+If another logdir is required, existing TensorBoard can be stopped from jupyter terminal using command **sudo systemctl stop tensorboard.service** and another one started instead of it from the terminal with command **source /opt/python/python3.7.9/bin/activate && export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/cudnn/lib64:/usr/local/cuda/lib64; tensorboard --host 0.0.0.0 --port 6006 --logdir=/var/log/tensorboard**  or from Jupyter UI with magic **%tensorboard --host 0.0.0.0 --port 6006 --logdir=/home/datalab-user/LOG_DIR**. 
+This TensorBoard will not be shown in Jupyter window, but can be accessed via TensorBoard URL from DataLab UI.
+
 ### Manage libraries <a name="manage_libraries"></a>
 
 On every analytical tool instance you can install additional libraries by clicking on gear icon <img src="doc/gear_icon.png" alt="gear" width="20"> in the "Actions" column for a needed Notebook and hit "Manage libraries":
@@ -199,7 +209,7 @@
 
 After clicking you see the window with 4 fields:
 -   Field for selecting an active resource to install libraries
--   Field for selecting group of packages (apt/yum, Python 2, Python 3, R, Java, Others)
+-   Field for selecting group of packages (apt/yum, Python 3, R, Java, Others)
 -   Field for search available packages with autocomplete feature (if it's gained) except Java dependencies. For Java library you should enter using the next format: "groupID:artifactID:versionID"
 -   Field for library version. It's an optional field.
 
@@ -211,7 +221,7 @@
 
 **Note:** Apt or Yum packages depend on your DataLab OS family.
 
-**Note:** In group Others you can find other Python (2/3) packages, which haven't classifiers of version.
+**Note:** In group Others you can find other Python (3) packages, which haven't classifiers of version.
 
 After selecting library, you can see it in the midle of the window and can delete it from this list before installation.
 
@@ -225,13 +235,13 @@
 
 ### Create image <a name="create_image"></a>
 
-Out of each analytical tool instance you can create an AMI image (notebook should be in Running status), including all libraries, which have been installed on it. You can use that AMI to speed-up provisioining of further analytical tool, if you want to re-use existing configuration. To create an AMI click on a gear icon <img src="doc/gear_icon.png" alt="gear" width="20"> in the "Actions" menu for a needed Notebook and hit "Create AMI":
+Out of each analytical tool instance you can create an AMI image (notebook should be in Running status), including all libraries, which have been installed on it. You can use that AMI to speed-up provisioining of further analytical tool, if you want to re-use existing configuration. To create an AMI click on the gear icon <img src="doc/gear_icon.png" alt="gear" width="20"> in the "Actions" menu for a needed Notebook and hit "Create AMI":
 
 <p align="center"> 
-    <img src="doc/notebook_menu_create_ami.png" alt="Notebook create_ami" width="150">
+    <img src="doc/notebook_menu_create_image.png" alt="Notebook create_image" width="150">
 </p>
 
-On "Create AMI" popup you should fill:
+On "Create AMI" pop-up you should fill out:
 -   text box for an AMI name (mandatory)
 -   text box for an AMI description (optional)
 
@@ -239,17 +249,96 @@
     <img src="doc/create_ami.png" alt="Create AMI" width="480">
 </p>
 
-After clicking on "Create" button the Notebook status changes to "Creating image". Once an image is created the Notebook status changes back to "Running".
+After clicking on the "Create" button the Notebook status changes to "Creating image" and this image shows up in the list of "Images" page. Once an image is created the Notebook status changes back to "Running" and image status - to "Active":
 
-To create new analytical environment from custom image click on "Create new" button on “List of Resources” page. 
+![Main Image Page](doc/main_image_page.png) 
 
-“Create analytical tool” popup shows up. Choose project, endpoint, template of a Notebook for which the custom image has been created:
+To create a new analytical environment from custom image click on the "Create new" button on “Resources” page. 
+
+“Create analytical tool” pop-up shows up. Choose project, endpoint, template of a Notebook for which the custom image has been created:
 
 <p align="center"> 
     <img src="doc/create_notebook_from_ami.png" alt="Create notebook from AMI" width="560">
 </p>
 
-Before clicking "Create" button you should choose the image from "Select AMI" and fill in the "Name" and "Instance shape". For Deeplearning notebook on GCP there is also a list of predefined images.
+Before clicking the "Create" button you should choose the image from "Select AMI" and fill out the "Name" and "Instance shape". For Deeplearning notebook on GCP there is also a list of predefined images.
+
+In addition, you can filter list of images by clicking on the "Filter" button:
+
+<p align="center"> 
+    <img src="doc/filter_image_popup.png" alt="Filter Image Popup" width="480">
+</p>
+
+Here you can filter by:
+- Image name - custom image name that has been assigned by user who has created the image
+- Status - current status of the image that inform user whether image is active or not
+- Endpoint - endpoint for the instance which was used to create the image
+- Template name - the name of the template (custom or cloud) which was used to create the instance and later the image
+- Sharing status - current status of the image that inform user whether image has been shared with other users or user groups
+
+As soon as you select one or several filtered options you can confirm the filter action by clicking the "Ok" button. 
+After confirmation the page is updated by filtered parameters.
+
+![Filter Image Popup](doc/filtered_images.png)
+
+On top of that, you have several options to clear filter by:
+- Clicking on blue cross icon <img src="doc/filter_cross_icon.png" alt="cross" width="20"> next to each column  - only the filtering for this column is cleared
+- Clicking on cross icon <img src="doc/filter_cross_icon.png" alt="cross" width="20"> near to blue activate filter button - all filters are cleared
+- Clicking  in each column in the "Filter image" pop-up
+
+You can share the image (only in "Active" status) with selected users/groups in the project or terminate it if you are an image creator. Creator is the user who has created the image. 
+To share or terminate image click on the gear icon <img src="doc/gear_icon.png" alt="gear" width="20"> in the "Actions" menu for a needed image and hit "Terminate" or "Share" button appropriately.
+
+<p align="center"> 
+    <img src="doc/image_action_menu.png" alt="Image action menu" width="150">
+</p>
+
+Confirmation pop-up for image termination:
+
+<p align="center"> 
+    <img src="doc/image_termination.png" alt="Image termination" width="500">
+</p>
+
+After you confirm your intent to terminate the image - the status changes to "Terminating" and later becomes "Terminated"
+
+Share image pop-up for image sharing:
+
+<p align="center"> 
+    <img src="doc/image_sharing.png" alt="Image sharing" width="500">
+</p>
+
+You can share the image  with individual users by entering a user login and with groups of users by entering the group name.
+
+As soon as you confirm image sharing the image status changes from "Private" to "Shared" status for user who shares the image. The shared image shows up in the list of images and has "Received" status for user with whom image is shared.
+
+In addition, the information about sharing is saved in the sharing pop-up window:
+
+<p align="center"> 
+    <img src="doc/information_about_sharing.png" alt="Information about sharing" width="400">
+</p>
+
+At any time you can stop sharing the image with other users by clicking on the cross next to users groups in the "Shared with" section.
+Once you click on the cross the confirmation pop-up window appears: 
+
+<p align="center"> 
+    <img src="doc/stop_sharing_confirmation.png" alt="Stop sharing confirmation" width="400">
+</p>
+
+As soon as you confirm stop sharing, the user login/group is deleted from the sharing pop-up window and from the images' table list of the user.
+
+You always have possibility to view image information by clicking the question icon <img src="doc/question.png" alt="question" width="20"> in the "Actions" column. Then the pop-up window with additional info shows up:
+
+<p align="center"> 
+    <img src="doc/image_additional_info.png" alt="Image info." width="450">
+</p>
+
+- Image status
+- Notebook template which was used for image creation
+- Which extra libraries were installed for the image
+- Cloud provider where image was created
+- Image creation date
+- Who created the image
+- With whom the image was shared.
 
 --------------------------
 ## Stop Notebook server <a name="notebook_stop"></a>
@@ -337,7 +426,15 @@
 
 To create Data Engine Service (Dataproc) with preemptible instances check off 'preemptible node count'. You can add from 1 to 11 preemptible instances.
 
-This picture shows menu for creating Standalone Apache Spark cluster for Azure and AWS:
+
+This picture shows menu for HDInsight creation for Azure:
+
+<p align="center"> 
+    <img src="doc/hdinsight.png" alt="Create HDInsight on Azure" width="760">
+</p>
+
+
+This picture shows menu for creating Standalone Apache Spark cluster for Azure, GCP and AWS:
 <p align="center"> 
     <img src="doc/spark_creating_menu.png" alt="Create Computational resource on Azure" width="760">
 </p>
@@ -362,9 +459,15 @@
 
 To do that open any of the analytical tools and select proper kernel/interpreter:
 
-**Jupyter** – go to Kernel and choose preferable interpreter between local and Computational resource ones. Currently we have added support of Python 2 (only for local kernel)/3, Spark, Scala, R in Jupyter.
+**Jupyter** – go to Kernel and choose preferable interpreter between local and Computational resource ones. Currently we have added support of Python 3, Spark, Scala, R in Jupyter.
 
-![Jupiter](doc/jupyter_kernel.png)
+![Jupyter](doc/jupyter_kernel.png)
+
+As you know, you can install library thanks to [Manage libraries functionality](#manage_libraries), but in addition you are supposed to install library via Jupyter cell using the next command (i.e., for Python group):
+
+<p align="center" class="facebox-popup"> 
+    <img src="doc/library_magic_usage.png" alt="Library magic usage" width="200">
+</p>
 
 **Zeppelin** – go to Interpreter Biding menu and switch between local and Computational resource there. Once needed interpreter is selected click on "Save".
 
@@ -373,7 +476,6 @@
 Insert following “magics” before blocks of your code to start executing your analytical jobs:
 
 -   interpreter\_name.%spark – for Scala and Spark;
--   interpreter\_name.%pyspark – for Python2;
 -   interpreter\_name.%pyspark3 – for Python3;
 -   interpreter\_name.%sparkr – for R;
 
@@ -534,8 +636,8 @@
 
 You are able to access to cloud buckets via DataLab Web UI.
 There are two ways to open bucket browser:
-- clicking on Notebook name on the "List of resources" page, where there is an "Open bucket browser" link;
-- clicking on "Bucket browser" bucket on the "List of resources" page.
+- clicking on Notebook name on the "Instances" page, where there is an "Open bucket browser" link;
+- clicking on "Bucket browser" bucket on the "Instances" page.
 
 ![Bucket_browser_button](doc/bucket_button.png)
 
@@ -557,6 +659,18 @@
 --------------------------------
 # Administration <a name="administration"></a>
 
+There are four pages in the "Administration" panel:
+
+<p align="center"> 
+    <img src="doc/administration_section.png" alt="Administration section" width="150">
+</p>
+
+- "Users" page, where administrator can assign appropriate permisions for users;
+- "Projects" page, where administrator can manage a project;
+- "Resources" page, where administrator monitor and manage project resources;
+- "Configuration" page, where administrator can view and change configuration files and restart DataLab services.
+
+
 ## Manage roles <a name="manage_roles"></a>
 
 Administrator can choose what instance shape(s), notebook(s) and computational resource are supposed to create for certain group(s) or user(s). Administrator can also assign administrator per project, who is able to manage roles within particular project.
@@ -612,14 +726,14 @@
 
 To terminate Edge node hit "Terminate edge node". After that confirm "OK" in confirmation popup. All related instances change its status to "Terminating" and soon become "Terminated".
 
-## Environment management <a name="environment_management"></a>
+## Resourses <a name="Resourses"></a>
 
-DataLab Environment Management page is an administration page allowing adminstrator to see the list of all users environments and to stop/terminate all of them.
+DataLab Resourses page is an administration page allowing adminstrator to see the list of all users environments and to stop/terminate all of them.
 
-To access Environment management page either navigate to it via main menu:
+To access Resourses page either navigate to it via main menu:
 
 <p align="center"> 
-    <img src="doc/environment_management.png" alt="Environment management">
+    <img src="doc/environment_management.png" alt="Resourses">
 </p>
 
 To stop or terminate the Notebook click on a gear icon <img src="doc/gear_icon.png" alt="gear" width="20"> in the "Actions" column for a needed Notebook and hit "Stop" or "Terminate" action:
@@ -744,7 +858,7 @@
 - who did the action
 - what the action was done
 
-Furthermore on the center of header you can choose period of report in datepicker.
+Furthermore, on the center of header you can choose period of report in datepicker.
 
 ![Audit page](doc/audit_page.png)
 
diff --git a/build.properties b/build.properties
index 622c600..db3dfa6 100644
--- a/build.properties
+++ b/build.properties
@@ -16,4 +16,4 @@
 # specific language governing permissions and limitations
 # under the License.
 #
-datalab.version=2.5
\ No newline at end of file
+datalab.version=2.6.0
\ No newline at end of file
diff --git a/doc/administration_section.png b/doc/administration_section.png
new file mode 100644
index 0000000..19e2e88
--- /dev/null
+++ b/doc/administration_section.png
Binary files differ
diff --git a/doc/audit_page.png b/doc/audit_page.png
index 7f26780..c1bac87 100644
--- a/doc/audit_page.png
+++ b/doc/audit_page.png
Binary files differ
diff --git a/doc/billing_page.png b/doc/billing_page.png
index cf3d554..a445674 100644
--- a/doc/billing_page.png
+++ b/doc/billing_page.png
Binary files differ
diff --git a/doc/bucket_button.png b/doc/bucket_button.png
index 0a0c9fb..68be640 100644
--- a/doc/bucket_button.png
+++ b/doc/bucket_button.png
Binary files differ
diff --git a/doc/configuration_page.png b/doc/configuration_page.png
index b1d055e..17c4287 100644
--- a/doc/configuration_page.png
+++ b/doc/configuration_page.png
Binary files differ
diff --git a/doc/configuration_page1.png b/doc/configuration_page1.png
index 58ac0de..08c9728 100644
--- a/doc/configuration_page1.png
+++ b/doc/configuration_page1.png
Binary files differ
diff --git a/doc/configuration_page_prov.png b/doc/configuration_page_prov.png
index 0dd8d53..d9cc361 100644
--- a/doc/configuration_page_prov.png
+++ b/doc/configuration_page_prov.png
Binary files differ
diff --git a/doc/configuration_page_restart.png b/doc/configuration_page_restart.png
index 1aedc6a..cd6e015 100644
--- a/doc/configuration_page_restart.png
+++ b/doc/configuration_page_restart.png
Binary files differ
diff --git a/doc/environment_management.png b/doc/environment_management.png
index 462201b..2d75cd0 100644
--- a/doc/environment_management.png
+++ b/doc/environment_management.png
Binary files differ
diff --git a/doc/filter_cross_icon.png b/doc/filter_cross_icon.png
new file mode 100644
index 0000000..83371ef
--- /dev/null
+++ b/doc/filter_cross_icon.png
Binary files differ
diff --git a/doc/filter_image_popup.png b/doc/filter_image_popup.png
new file mode 100644
index 0000000..217fd7d
--- /dev/null
+++ b/doc/filter_image_popup.png
Binary files differ
diff --git a/doc/filtered_images.png b/doc/filtered_images.png
new file mode 100644
index 0000000..3cc2482
--- /dev/null
+++ b/doc/filtered_images.png
Binary files differ
diff --git a/doc/hdinsight.png b/doc/hdinsight.png
new file mode 100644
index 0000000..b0f8b05
--- /dev/null
+++ b/doc/hdinsight.png
Binary files differ
diff --git a/doc/image_action_menu.png b/doc/image_action_menu.png
new file mode 100644
index 0000000..314de80
--- /dev/null
+++ b/doc/image_action_menu.png
Binary files differ
diff --git a/doc/image_additional_info.png b/doc/image_additional_info.png
new file mode 100644
index 0000000..c20f50a
--- /dev/null
+++ b/doc/image_additional_info.png
Binary files differ
diff --git a/doc/image_sharing.png b/doc/image_sharing.png
new file mode 100644
index 0000000..85c7c4b
--- /dev/null
+++ b/doc/image_sharing.png
Binary files differ
diff --git a/doc/image_termination.png b/doc/image_termination.png
new file mode 100644
index 0000000..83e388b
--- /dev/null
+++ b/doc/image_termination.png
Binary files differ
diff --git a/doc/information_about_sharing.png b/doc/information_about_sharing.png
new file mode 100644
index 0000000..54e7c3a
--- /dev/null
+++ b/doc/information_about_sharing.png
Binary files differ
diff --git a/doc/jupyter_kernel.png b/doc/jupyter_kernel.png
index d718824..d8c0f87 100644
--- a/doc/jupyter_kernel.png
+++ b/doc/jupyter_kernel.png
Binary files differ
diff --git a/doc/library_magic_usage.png b/doc/library_magic_usage.png
new file mode 100644
index 0000000..2913926
--- /dev/null
+++ b/doc/library_magic_usage.png
Binary files differ
diff --git a/doc/main_image_page.png b/doc/main_image_page.png
new file mode 100644
index 0000000..d478591
--- /dev/null
+++ b/doc/main_image_page.png
Binary files differ
diff --git a/doc/main_page.png b/doc/main_page.png
index e0230b8..de5f64c 100644
--- a/doc/main_page.png
+++ b/doc/main_page.png
Binary files differ
diff --git a/doc/main_page_filter.png b/doc/main_page_filter.png
index 96c5fdc..4ede541 100644
--- a/doc/main_page_filter.png
+++ b/doc/main_page_filter.png
Binary files differ
diff --git a/doc/notebook_menu_create_ami.png b/doc/notebook_menu_create_ami.png
deleted file mode 100644
index 49f101d..0000000
--- a/doc/notebook_menu_create_ami.png
+++ /dev/null
Binary files differ
diff --git a/doc/notebook_menu_create_image.png b/doc/notebook_menu_create_image.png
new file mode 100644
index 0000000..0525f55
--- /dev/null
+++ b/doc/notebook_menu_create_image.png
Binary files differ
diff --git a/doc/notebook_menu_manage_libraries.png b/doc/notebook_menu_manage_libraries.png
index 1db4614..1368589 100644
--- a/doc/notebook_menu_manage_libraries.png
+++ b/doc/notebook_menu_manage_libraries.png
Binary files differ
diff --git a/doc/notebook_menu_scheduler.png b/doc/notebook_menu_scheduler.png
index b842fa8..c551ab1 100644
--- a/doc/notebook_menu_scheduler.png
+++ b/doc/notebook_menu_scheduler.png
Binary files differ
diff --git a/doc/notebook_menu_stop.png b/doc/notebook_menu_stop.png
index 9907bcc..20f1db4 100644
--- a/doc/notebook_menu_stop.png
+++ b/doc/notebook_menu_stop.png
Binary files differ
diff --git a/doc/question.png b/doc/question.png
new file mode 100644
index 0000000..941de78
--- /dev/null
+++ b/doc/question.png
Binary files differ
diff --git a/doc/stop_sharing_confirmation.png b/doc/stop_sharing_confirmation.png
new file mode 100644
index 0000000..d16de61
--- /dev/null
+++ b/doc/stop_sharing_confirmation.png
Binary files differ
diff --git a/doc/upload_or_generate_user_key.png b/doc/upload_or_generate_user_key.png
index 95b624f..b5d50e4 100644
--- a/doc/upload_or_generate_user_key.png
+++ b/doc/upload_or_generate_user_key.png
Binary files differ
diff --git a/doc/user.png b/doc/user.png
new file mode 100644
index 0000000..1512717
--- /dev/null
+++ b/doc/user.png
Binary files differ
diff --git a/doc/user_information.png b/doc/user_information.png
new file mode 100644
index 0000000..1e9ce4c
--- /dev/null
+++ b/doc/user_information.png
Binary files differ
diff --git a/infrastructure-provisioning/pom.xml b/infrastructure-provisioning/pom.xml
new file mode 100644
index 0000000..66608bc
--- /dev/null
+++ b/infrastructure-provisioning/pom.xml
@@ -0,0 +1,39 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.epam.datalab</groupId>
+        <artifactId>datalab</artifactId>
+        <version>1.0</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>devops</artifactId>
+    <name>DevOps Module</name>
+
+    <properties>
+        <sonar.language>py</sonar.language>
+    </properties>
+
+    <build>
+        <sourceDirectory>.</sourceDirectory>
+    </build>
+</project>
\ No newline at end of file
diff --git a/infrastructure-provisioning/scripts/deploy_datalab.py b/infrastructure-provisioning/scripts/deploy_datalab.py
index 34be5ec..6f46bf7 100644
--- a/infrastructure-provisioning/scripts/deploy_datalab.py
+++ b/infrastructure-provisioning/scripts/deploy_datalab.py
@@ -114,6 +114,8 @@
                         help='Column name in report file that contains cost tag')
     parser.add_argument('--resource_id', type=str, default='line_item_resource_id',
                         help='Column name in report file that contains datalab resource id tag')
+    parser.add_argument('--conf_bucket_versioning_enabled', type=str, default='true', choices=BOOL_CHOICES_LIST,
+                            help='Versioning for S3 bucket (valid choices: %s)' % BOOL_CHOICES_LIST)
 
     parser.add_argument('--tags', type=str, default='line_item_operation,line_item_line_item_description',
                         help='Column name in report file that contains tags')
@@ -135,7 +137,7 @@
         multiple emails, e.g. u1@example.com,u2@example.com.''')
     parser.add_argument('--conf_repository_user', type=str, default='',
                         help='user to access repository (used for jars download)')
-    parser.add_argument('--conf_release_tag', type=str, default='2.5.1',
+    parser.add_argument('--conf_release_tag', type=str, default='2.6.0',
                         help='tag used for jars download')
     parser.add_argument('--conf_repository_pass', type=str, default='',
                         help='password to access repository (used for jars download)')
@@ -210,6 +212,8 @@
     aws_parser.add_argument('--aws_report_path', type=str, help='The path to billing reports directory in S3 bucket')
     aws_parser.add_argument('--aws_permissions_boundary_arn', type=str, default='',
                             help='Permission boundary to be attached to new roles')
+    aws_parser.add_argument('--aws_ssn_instance_role', type=str, default='',
+                            help='Role to be attached to SSN instance')
 
     aws_required_args = aws_parser.add_argument_group('Required arguments')
     aws_required_args.add_argument('--aws_region', type=str, required=True, help='AWS region')
@@ -257,6 +261,20 @@
                             help='One of more comma-separated GCP Firewall rules for SSN')
     gcp_parser.add_argument('--gcp_ssn_instance_size', type=str, default='n1-standard-2',
                                    help='The SSN instance shape')
+    gcp_parser.add_argument('--gcp_os_login_enabled', type=str, default='FALSE',
+                            help='"TRUE" to enable os login for gcp instances')
+    gcp_parser.add_argument('--gcp_block_project_ssh_keys', type=str, default='FALSE',
+                            help='"TRUE" to block project ssh keys for gcp instances')
+    gcp_parser.add_argument('--gcp_cmek_resource_name', type=str, default='',
+                            help='customer managed encryption key resource name '
+                            'e.g. projects/{project_name}/locations/{us}/keyRings/{keyring_name}/cryptoKeys/{key_name}')
+    gcp_parser.add_argument('--gcp_storage_lifecycle_rules', type=str, default='',
+                            help='storage bucket lifecycle rules')
+    gcp_parser.add_argument('--gcp_wrapped_csek', type=str, default='',
+                            help='customer supplied encryption key for disk/image encryption in RFC 4648 base64 '
+                                 'encoded, RSA-wrapped 2048-bit format as rsaEncryptedKey')
+    gcp_parser.add_argument('--gcp_jupyter_gpu_type', type=str, default='nvidia-tesla-a100',
+                            help='gpu type for jupyter gpu notebooks with a2-highgpu-1g shape')
 
     gcp_required_args = gcp_parser.add_argument_group('Required arguments')
     gcp_required_args.add_argument('--gcp_region', type=str, required=True, help='GCP region')
diff --git a/infrastructure-provisioning/scripts/deploy_repository/templates/nexus.conf b/infrastructure-provisioning/scripts/deploy_repository/templates/nexus.conf
index a4201d2..f48079c 100644
--- a/infrastructure-provisioning/scripts/deploy_repository/templates/nexus.conf
+++ b/infrastructure-provisioning/scripts/deploy_repository/templates/nexus.conf
@@ -61,8 +61,8 @@
     ssl_session_timeout 1d;
     ssl_session_cache shared:SSL:50m;
     ssl_session_tickets off;
-    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
+    ssl_protocols TLSv1.2 TLSv1.3;
+    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:!DSS';
     ssl_prefer_server_ciphers on;
     ssl_dhparam /etc/ssl/certs/dhparam.pem;
 
diff --git a/infrastructure-provisioning/src/base/scripts/configure_keycloak.py b/infrastructure-provisioning/src/base/scripts/configure_keycloak.py
index 5974b2c..449177c 100644
--- a/infrastructure-provisioning/src/base/scripts/configure_keycloak.py
+++ b/infrastructure-provisioning/src/base/scripts/configure_keycloak.py
@@ -40,6 +40,7 @@
 parser.add_argument('--hostname', type=str, default='')
 parser.add_argument('--project_name', type=str, default='')
 parser.add_argument('--endpoint_name', type=str, default='')
+parser.add_argument('--exploratory_name', type=str, default='')
 args = parser.parse_args()
 
 ##############
@@ -50,6 +51,7 @@
         logging.info('[CONFIGURE KEYCLOAK]')
         keycloak_auth_server_url = '{}/realms/master/protocol/openid-connect/token'.format(
             args.keycloak_auth_server_url)
+
         keycloak_auth_data = {
             "username": args.keycloak_user,
             "password": args.keycloak_user_password,
@@ -63,28 +65,42 @@
         keycloak_client_create_url = '{0}/admin/realms/{1}/clients'.format(args.keycloak_auth_server_url,
                                                                            args.keycloak_realm_name)
         if args.project_name and args.endpoint_name:
-            keycloak_client_name = "{0}-{1}-{2}".format(args.service_base_name, args.project_name, args.endpoint_name)
+            if args.exploratory_name:
+                keycloak_client_name = "{0}-{1}-{2}-{3}".format(args.service_base_name, args.project_name,
+                                                                args.endpoint_name, args.exploratory_name)
+            else:
+                keycloak_client_name = "{0}-{1}-{2}".format(args.service_base_name, args.project_name,
+                                                            args.endpoint_name)
         else:
             keycloak_client_name = "{0}-ui".format(args.service_base_name)
+
         keycloak_client_id = str(uuid.uuid4())
-        if args.hostname == '':
+
+        if not args.hostname:
             keycloak_redirectUris = 'https://{0}/*,http://{0}/*'.format(args.instance_public_ip).lower().split(',')
         else:
             keycloak_redirectUris = 'https://{0}/*,http://{0}/*,https://{1}/*,http://{1}/*'.format(
                 args.instance_public_ip, args.hostname).lower().split(',')
+
         keycloak_client_data = {
             "clientId": keycloak_client_name,
             "id": keycloak_client_id,
             "enabled": "true",
-            "redirectUris": keycloak_redirectUris,
             "publicClient": "false",
             "secret": args.keycloak_client_secret,
             "protocol": "openid-connect",
         }
 
+        if not args.exploratory_name:
+            keycloak_client_data["redirectUris"] = keycloak_redirectUris
+
         if not args.project_name:
             keycloak_client_data["serviceAccountsEnabled"] = "true"
 
+        if args.exploratory_name:
+            keycloak_client_data["standardFlowEnabled"] = "false"
+            keycloak_client_data["serviceAccountsEnabled"] = "true"
+
         try:
             keycloak_token = requests.post(keycloak_auth_server_url, data=keycloak_auth_data, verify=False).json()
             keycloak_client = requests.post(keycloak_client_create_url, json=keycloak_client_data,
diff --git a/infrastructure-provisioning/src/base/scripts/create_ssh_user.py b/infrastructure-provisioning/src/base/scripts/create_ssh_user.py
index 183295c..3af70e5 100644
--- a/infrastructure-provisioning/src/base/scripts/create_ssh_user.py
+++ b/infrastructure-provisioning/src/base/scripts/create_ssh_user.py
@@ -57,7 +57,7 @@
 if __name__ == "__main__":
     print("Configure connections")
     global conn
-    conn = datalab.fab.init_datalab_connection(args.hostname, args.initial_user, args.keyfile)
+    conn = datalab.fab.init_datalab_connection(args.hostname, args.initial_user, args.keyfile, args.os_user)
     print("Creating ssh user: {}".format(args.os_user))
     try:
         ensure_ssh_user(args.initial_user, args.os_user, args.sudo_group)
diff --git a/infrastructure-provisioning/src/base/scripts/install_prerequisites.py b/infrastructure-provisioning/src/base/scripts/install_prerequisites.py
index 430805f..b88b789 100644
--- a/infrastructure-provisioning/src/base/scripts/install_prerequisites.py
+++ b/infrastructure-provisioning/src/base/scripts/install_prerequisites.py
@@ -36,7 +36,10 @@
 parser.add_argument('--hostname', type=str, default='')
 parser.add_argument('--keyfile', type=str, default='')
 parser.add_argument('--pip_packages', type=str,
-                    default='boto3 argparse fabric awscli google-api-python-client google-auth-httplib2 google-cloud-storage pycryptodome azure==2.0.0')
+                    default='boto3 argparse fabric awscli google-api-python-client google-auth-httplib2 '
+                            'google-cloud-storage pycryptodome azure-storage-blob azure-datalake-store '
+                            'azure-mgmt-compute azure-mgmt-network azure-mgmt-resource azure-mgmt-storage '
+                            'azure-mgmt-datalake-store azure-identity azure-mgmt-hdinsight')
 parser.add_argument('--additional_config', type=str, default='{"empty":"string"}')
 parser.add_argument('--user', type=str, default='')
 parser.add_argument('--edge_private_ip', type=str, default='')
@@ -60,8 +63,8 @@
         traceback.print_exc()
         sys.exit(1)
 
-    #logging.info("Disable scp on nodes")
-    #disable_edge_scp_binary(args.user)
+    logging.info("Disable scp on nodes")
+    remove_scp_nmap_binary(args.user)
 
     #logging.info("Updating openssh to version")
     #ensure_openssh_version(args.user)
diff --git a/infrastructure-provisioning/src/base/scripts/install_user_key.py b/infrastructure-provisioning/src/base/scripts/install_user_key.py
index 2e68abd..1de241b 100644
--- a/infrastructure-provisioning/src/base/scripts/install_user_key.py
+++ b/infrastructure-provisioning/src/base/scripts/install_user_key.py
@@ -53,6 +53,7 @@
         conn.sudo('echo "{0}" >> /home/{1}/.ssh/authorized_keys'.format(key, args.user))
     except:
         print('No user key')
+    conn.sudo('chmod 600 /home/{0}/.ssh/authorized_keys'.format(args.user))
 
 ##############
 # Run script #
diff --git a/infrastructure-provisioning/src/dataengine-service/fabfile.py b/infrastructure-provisioning/src/dataengine-service/fabfile.py
index 74797b8..e05849b 100644
--- a/infrastructure-provisioning/src/dataengine-service/fabfile.py
+++ b/infrastructure-provisioning/src/dataengine-service/fabfile.py
@@ -25,13 +25,15 @@
 import os
 import sys
 import uuid
+import secrets
 import subprocess
+import random
+import string
 from datalab.actions_lib import *
 from datalab.fab import *
 from datalab.meta_lib import *
 from fabric import *
 
-
 @task
 def run(ctx):
     local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
@@ -41,16 +43,21 @@
                         level=logging.INFO,
                         filename=local_log_filepath)
     dataengine_service_config = dict()
-    dataengine_service_config['uuid'] = str(uuid.uuid4())[:5]
+    dataengine_service_config['uuid'] = '{}{}'.format(random.choice(string.ascii_lowercase), str(uuid.uuid4())[:5])
+    dataengine_service_config['access_password'] = secrets.token_urlsafe(32)
     try:
-        subprocess.run("~/scripts/{}.py --uuid {}".format('dataengine-service_prepare', dataengine_service_config['uuid']), shell=True, check=True)
+        subprocess.run("~/scripts/{}.py --uuid {} --access_password {}"
+                       .format('dataengine-service_prepare', dataengine_service_config['uuid'],
+                               dataengine_service_config['access_password']), shell=True, check=True)
     except Exception as err:
         traceback.print_exc()
         append_result("Failed preparing Data Engine service.", str(err))
         sys.exit(1)
 
     try:
-        subprocess.run("~/scripts/{}.py --uuid {}".format('dataengine-service_configure', dataengine_service_config['uuid']), shell=True, check=True)
+        subprocess.run("~/scripts/{}.py --uuid {} --access_password {}"
+                       .format('dataengine-service_configure', dataengine_service_config['uuid'],
+                               dataengine_service_config['access_password']), shell=True, check=True)
     except Exception as err:
         traceback.print_exc()
         append_result("Failed configuring Data Engine service.", str(err))
diff --git a/infrastructure-provisioning/src/deeplearning/scripts/configure_deep_learning_node.py b/infrastructure-provisioning/src/deeplearning/scripts/configure_deep_learning_node.py
index 87f098f..ea20219 100644
--- a/infrastructure-provisioning/src/deeplearning/scripts/configure_deep_learning_node.py
+++ b/infrastructure-provisioning/src/deeplearning/scripts/configure_deep_learning_node.py
@@ -66,7 +66,7 @@
 if os.environ['conf_cloud_provider'] == 'azure':
     os.environ['notebook_python_venv_version'] = '3.7.12'
 python_venv_version = os.environ['notebook_python_venv_version']
-python_venv_path = '/opt/python/python{}/'.format(python_venv_version)
+python_venv_path = '/opt/python/python{0}/bin/python{1}'.format(python_venv_version, python_venv_version[:3])
 
 if args.region == 'cn-north-1':
     spark_link = "http://mirrors.hust.edu.cn/apache/spark/spark-" + spark_version + "/spark-" + spark_version + \
@@ -95,7 +95,9 @@
 
 def configure_jupyterlab_at_gcp_image(os_user, exploratory_name):
     if not exists(conn, '/home/{}/.ensure_dir/jupyterlab_ensured'.format(os_user)):
-        jupyter_conf_file = '/home/jupyter/.jupyter/jupyter_notebook_config.py'
+        #jupyter_conf_file = '/home/jupyter/.jupyter/jupyter_notebook_config.py'
+        jupyter_conf_file = '/home/{}/.jupyter/jupyter_lab_config.py'.format(os_user)
+        conn.run('/opt/conda/bin/python3.7 /opt/conda/bin/jupyter-lab --generate-config')
         conn.sudo('''bash -l -c 'sed -i "s|c.NotebookApp|#c.NotebookApp|g" {}' '''.format(jupyter_conf_file))
         conn.sudo('''bash -l -c "echo 'c.NotebookApp.ip = \\"0.0.0.0\\" ' >> {}" '''.format(jupyter_conf_file))
         conn.sudo('''bash -l -c "echo 'c.NotebookApp.port = 8888' >> {}" '''.format(jupyter_conf_file))
@@ -106,6 +108,7 @@
         conn.sudo('''bash -l -c "echo 'c.NotebookApp.cookie_secret = b\\"{0}\\"' >> {1}" '''.format(id_generator(),
                                                                                                     jupyter_conf_file))
         conn.sudo('''bash -l -c "echo \\"c.NotebookApp.token = u''\\" >> {}" '''.format(jupyter_conf_file))
+        conn.sudo('cp /home/{}/.jupyter/jupyter_lab_config.py /home/jupyter/.jupyter/jupyter_notebook_config.py'.format(os_user))
         conn.sudo('systemctl restart jupyter')
         conn.sudo('touch /home/{}/.ensure_dir/jupyterlab_ensured'.format(os_user))
 
diff --git a/infrastructure-provisioning/src/edge/templates/locations/jupyter-gpu.conf b/infrastructure-provisioning/src/edge/templates/locations/jupyter-gpu.conf
new file mode 100644
index 0000000..56f98ed
--- /dev/null
+++ b/infrastructure-provisioning/src/edge/templates/locations/jupyter-gpu.conf
@@ -0,0 +1,29 @@
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+location ~* /{{ NAME }}/.* {
+    proxy_pass http://{{ IP }}:8888;
+    proxy_set_header Host $http_host;
+    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+    proxy_set_header X-Real-IP $remote_addr;
+    proxy_http_version 1.1;
+    proxy_set_header Upgrade $http_upgrade;
+    proxy_set_header Connection "upgrade";
+}
diff --git a/infrastructure-provisioning/src/general/conf/datalab.ini b/infrastructure-provisioning/src/general/conf/datalab.ini
index 0d38f43..dc7aed0 100644
--- a/infrastructure-provisioning/src/general/conf/datalab.ini
+++ b/infrastructure-provisioning/src/general/conf/datalab.ini
@@ -61,7 +61,7 @@
 ### Additional tags in format 'Key1:Value1;Key2:Value2'
 # additional_tags =
 ### pip version
-pip_version = 21.0.1
+pip_version = 21.1.1
 ### openssh version
 openssh_version = 8.8p1
 ### Billing tag key
@@ -100,6 +100,8 @@
 # download_docker_images =
 ### release tag
 # release_tag =
+### bucket versioning
+bucket_versioning_enabled = false
 ### Deeplearning native cloud AMI enabled
 deeplearning_cloud_ami = true
 
@@ -159,7 +161,7 @@
 ### Amazon zone letter for ssn, edge and notebook subnet provisioning
 # zone =
 ### Amazon ami name based on debian conf_os_family for all DataLab instances
-debian_image_name = ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-20201026
+debian_image_name = ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-20220914
 ### Amazon ami name based on RedHat conf_os_family for all DataLab instances
 redhat_image_name = RHEL-7.4_HVM-20180103-x86_64-2-Hourly2-GP2
 ### Amazon account ID
@@ -228,6 +230,16 @@
 # subnet_name =
 ### Names of the firewall rules for SSN
 # firewall_rules =
+### True if os login is enabled for instances
+os_login_enabled = FALSE
+### True if block_project_ssh_keys is enabled for instances
+block_project_ssh_keys = FALSE
+### gcp customer managed encryption key to use
+# cmek_resource_name =
+### gcp customer managed encryption key to use
+# storage_lifecycle_rules =
+### gcp customer supplied wrapped encryption key to use
+# wrapped_csek =
 ### GCP region name for whole DataLab provisioning
 region = us-west1
 ### GCP zone name for whole DataLab provisioning
@@ -243,6 +255,8 @@
 edge_instance_size = n1-standard-1
 ### GPU type for Tensor/DeepLaerning notebooks
 gpu_accelerator_type = nvidia-tesla-k80
+### GPU type for jupyter-gpu and jupyter-conda notebooks
+jupyter_gpu_type = nvidia-tesla-a100
 
 #--- [ssn] section contains all parameters that are using for self-service node provisioning ---#
 [ssn]
@@ -260,6 +274,9 @@
 # subdomain =
 ### Role ARN for creating Route53 record
 # assume_role_arn =
+### guacamole/guacamole image tag
+guacamole_image_tag = 1.4.0
+
 
 #--- [edge] section contains all parameters that are using for edge node provisioning ---#
 [edge]
@@ -269,6 +286,8 @@
 # elastic_ip =
 ### Edge node is NAT
 is_nat = true
+### Edge openresty version
+openresty_version = 1.19.3.2-1~focal1
 
 #--- [notebook] section contains all parameters that are using for all notebooks provisioning ---#
 [notebook]
@@ -279,18 +298,18 @@
 ### Version of Apache Spark to be installed on notebook
 spark_version = 3.0.1
 ### Version of Apache Hadoop to be installed on notebook
-hadoop_version = 2.7
+hadoop_version = 3.2
 ### Version of Jupyter to be installed on notebook
-jupyter_version = 6.1.6
+jupyter_version = 6.4.12
 ### Version of Python to be installed as virualenv on notebook
 python_venv_version = 3.7.9
 ### Version of TensorFlow to be installed on notebook
-tensorflow_version = 2.5.0
+tensorflow_version = 2.9.1
 ### Version of Zeppelin to be installed on notebook
 zeppelin_version = 0.9.1
 ### Version of Rstudio to be installed on notebook
 #rstudio_version = 1.4.1103
-rstudio_version = 2021.09.1-372
+rstudio_version = 2022.02.2-485
 ### Version of Scala to be installed on notebook
 scala_version = 2.12.8
 ### Version of Livy top be installed on notebook
@@ -331,7 +350,7 @@
 ### Version of ungit if previous needed. Use latest as default.
 ungit_version = 1.5.15
 ### Numpy version
-numpy_version = 1.18.3
+numpy_version = 1.18.5
 ### caTools version for R 3.4.4
 catools_version = 1.17.1.4
 ### pbdZMQ version for R 3.4.4
@@ -341,15 +360,23 @@
 ### Matplotlib version
 matplotlib_version = 3.3.4
 ### JupyterLab image
-jupyterlab_image = odahu\/base-notebook:1.1.0-rc8
+jupyterlab_image = jupyter\/base-notebook:lab-3.4.3
 ### Superset version
-superset_version = 0.35.1
+superset_version = 1.5.1
 ### GCS-connector version
 gcs_connector_version = 2.0.1
 ### Setuptools version
-setuptools_version = 54.1.1
+setuptools_version = 59.6.0
 ### Roxygen2 version
 roxygen2_version = 7.1.1
+### Nbconvert version
+nbconvert_version = 5.6.1
+### nbformat_version
+nbformat_version = 5.1.3
+### jupyterlab version
+jupyterlab_version = 3.4.3
+### jupyter keycloak client creation
+create_keycloak_client = False
 
 #--- [emr] section contains all parameters that are using for emr provisioning ---#
 [emr]
@@ -381,7 +408,7 @@
 ### Count of slave nodes for Data Engine
 # instance_count =
 ### Type of notebooks for creating Data Engine from notebook images
-image_notebooks = jupyter,jupyterlab,rstudio,zeppelin,tensor,tensor-rstudio,deeplearning
+image_notebooks = jupyter,jupyter-gpu,jupyterlab,rstudio,zeppelin,tensor,tensor-rstudio,tensor-jupyterlab,deeplearning
 ### Persent of RAM allocated for an operating system
 os_memory = 75
 ### Explicit allocation RAM for an operating system
@@ -420,4 +447,4 @@
 #--- [reverse_proxy] reverse proxy settings ---#
 [reverse_proxy]
 ### Nginx version
-nginx_version = 1.15.1
\ No newline at end of file
+nginx_version = 1.15.1
diff --git a/infrastructure-provisioning/src/general/files/aws/base_Dockerfile b/infrastructure-provisioning/src/general/files/aws/base_Dockerfile
index 0ab23d5..2fe9207 100644
--- a/infrastructure-provisioning/src/general/files/aws/base_Dockerfile
+++ b/infrastructure-provisioning/src/general/files/aws/base_Dockerfile
@@ -26,7 +26,7 @@
 # Install any .deb dependecies
 RUN	apt-get update && \
     apt-get -y upgrade && \
-    DEBIAN_FRONTEND=noninteractive apt-get -y install python3-pip python3-dev python3-virtualenv groff vim less git wget nano libssl-dev libffi-dev libffi7 && \
+    DEBIAN_FRONTEND=noninteractive apt-get -y install python3-pip python3-dev python3-virtualenv groff vim less git wget nano libssl-dev libffi-dev libffi7 rsync && \
     apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
 
 # To cahnge POSIX locale to en_US.UTF-8
diff --git a/infrastructure-provisioning/src/general/files/aws/dataengine_description.json b/infrastructure-provisioning/src/general/files/aws/dataengine_description.json
index 3594e96..f6b772a 100644
--- a/infrastructure-provisioning/src/general/files/aws/dataengine_description.json
+++ b/infrastructure-provisioning/src/general/files/aws/dataengine_description.json
@@ -5,6 +5,7 @@
     "computation_resources_shapes":
     {
       "For testing" : [
+        {"Size": "S", "Description": "c4.large", "Type": "c4.large","Ram": "3.75 GB","Cpu": "2"},
         {"Size": "S", "Description": "c4.xlarge", "Type": "c4.xlarge","Ram": "7.5 GB","Cpu": "4"}
       ],
       "Memory optimized" : [
@@ -14,6 +15,7 @@
         {"Size": "L", "Description": "r3.8xlarge", "Type": "r3.8xlarge","Ram": "244 GB","Cpu": "32"}
       ],
       "Compute optimized": [
+        {"Size": "S", "Description": "c4.large", "Type": "c4.large","Ram": "3.75 GB","Cpu": "2"},
         {"Size": "S", "Description": "c4.xlarge", "Type": "c4.xlarge","Ram": "7.5 GB","Cpu": "4"},
         {"Size": "M", "Description": "c4.2xlarge", "Type": "c4.2xlarge","Ram": "15.0 GB","Cpu": "8"},
         {"Size": "L", "Description": "c4.8xlarge", "Type": "c4.8xlarge","Ram": "60.0 GB","Cpu": "36"}
diff --git a/infrastructure-provisioning/src/general/files/aws/deeplearning_description.json b/infrastructure-provisioning/src/general/files/aws/deeplearning_description.json
index 06f671a..fe2e3cd 100644
--- a/infrastructure-provisioning/src/general/files/aws/deeplearning_description.json
+++ b/infrastructure-provisioning/src/general/files/aws/deeplearning_description.json
@@ -8,10 +8,10 @@
   "exploratory_environment_versions" :
   [
     {
-      "template_name": "Deep Learning AMI Version 42.1",
-      "description": "MXNet-1.8.0 & 1.7.0, TensorFlow-2.4.1, 2.1.3 & 1.15.5, PyTorch-1.4.0 & 1.8.0, Neuron, & others. NVIDIA CUDA, cuDNN, NCCL, Intel MKL-DNN, Docker, NVIDIA-Docker & EFA support. Uses Anaconda virtual environments, configured to keep the different framework installations separate and easy to switch between frameworks as Jupyter kernels.",
+      "template_name": "Deep Learning AMI Version 60.2",
+      "description": "MXNet-1.8, TensorFlow-2.7, PyTorch-1.10, Neuron, & others. NVIDIA CUDA, cuDNN, NCCL, Intel MKL-DNN, Docker, NVIDIA-Docker & EFA support. For fully managed experience, check: https://aws.amazon.com/sagemaker",
       "environment_type": "exploratory",
-      "version": "Deep Learning AMI (Ubuntu 18.04) Version 42.1",
+      "version": "Deep Learning AMI (Ubuntu 18.04) Version 60.2",
       "vendor": "AWS"
     }
   ],
diff --git a/infrastructure-provisioning/src/general/files/aws/jupyter_description.json b/infrastructure-provisioning/src/general/files/aws/jupyter_description.json
index accfd94..57863b7 100644
--- a/infrastructure-provisioning/src/general/files/aws/jupyter_description.json
+++ b/infrastructure-provisioning/src/general/files/aws/jupyter_description.json
@@ -19,10 +19,10 @@
   "exploratory_environment_versions" :
   [
     {
-      "template_name": "Jupyter notebook 6.1.6",
+      "template_name": "Jupyter 6.4.12",
       "description": "Base image with Jupyter node creation routines",
       "environment_type": "exploratory",
-      "version": "jupyter_notebook-6.1.6",
+      "version": "jupyter_notebook-6.4.12",
       "vendor": "AWS"
     }
   ]
diff --git a/infrastructure-provisioning/src/general/files/aws/jupyterlab_description.json b/infrastructure-provisioning/src/general/files/aws/jupyterlab_description.json
index 487586f..3e00369 100644
--- a/infrastructure-provisioning/src/general/files/aws/jupyterlab_description.json
+++ b/infrastructure-provisioning/src/general/files/aws/jupyterlab_description.json
@@ -19,10 +19,10 @@
   "exploratory_environment_versions" :
   [
     {
-      "template_name": "JupyterLab 0.35.6",
+      "template_name": "JupyterLab 3.4.3",
       "description": "Base image with JupyterLab node creation routines",
       "environment_type": "exploratory",
-      "version": "jupyter_lab-0.35.6",
+      "version": "jupyter_lab-3.4.3",
       "vendor": "AWS"
     }
   ]
diff --git a/infrastructure-provisioning/src/general/files/aws/rstudio_description.json b/infrastructure-provisioning/src/general/files/aws/rstudio_description.json
index cef87d8..70e9ef0 100644
--- a/infrastructure-provisioning/src/general/files/aws/rstudio_description.json
+++ b/infrastructure-provisioning/src/general/files/aws/rstudio_description.json
@@ -19,10 +19,10 @@
   "exploratory_environment_versions" :
   [
     {
-      "template_name": "RStudio 2021.09.1-372",
+      "template_name": "RStudio 2022.02.2-485",
       "description": "Base image with RStudio node creation routines",
       "environment_type": "exploratory",
-      "version": "RStudio-2021.09.1-372",
+      "version": "RStudio-2022.02.2-485",
       "vendor": "AWS"
     }
   ]
diff --git a/infrastructure-provisioning/src/general/files/aws/ssn_policy.json b/infrastructure-provisioning/src/general/files/aws/ssn_policy.json
index 89f28c5..4348e4c 100644
--- a/infrastructure-provisioning/src/general/files/aws/ssn_policy.json
+++ b/infrastructure-provisioning/src/general/files/aws/ssn_policy.json
@@ -2,121 +2,124 @@
     "Version": "2012-10-17",
     "Statement": [
         {
+            "Effect": "Allow",
             "Action": [
+                "ec2:AuthorizeSecurityGroupIngress",
+                "ec2:DeleteSubnet",
+                "ec2:DescribeInstances",
+                "ec2:CreateImage",
+                "ec2:DeleteRouteTable",
+                "ec2:AssociateRouteTable",
+                "ec2:StartInstances",
+                "ec2:CreateRoute",
+                "ec2:RevokeSecurityGroupEgress",
+                "ec2:DescribeRouteTables",
+                "ec2:CreateTags",
+                "ec2:CreateRouteTable",
+                "ec2:RunInstances",
+                "ec2:DeregisterImage",
+                "ec2:DeleteSnapshot",
+                "ec2:DescribeAddresses",
+                "ec2:CreateVpcEndpoint",
+                "ec2:DescribeVpcs",
+                "ec2:DeleteSecurityGroup",
+                "ec2:AllocateAddress",
+                "ec2:DescribeSecurityGroups",
+                "ec2:DescribeImages",
+                "ec2:AuthorizeSecurityGroupEgress",
+                "ec2:TerminateInstances",
+                "ec2:StopInstances",
+                "ec2:RevokeSecurityGroupIngress",
+                "ec2:CreateSubnet",
+                "ec2:AssociateAddress",
+                "ec2:DescribeSubnets",
+                "ec2:ModifyVpcEndpoint",
+                "ec2:DisassociateAddress",
+                "ec2:ReleaseAddress",
+                "ec2:DeleteTags",
+                "ec2:DescribeSpotInstanceRequests",
+                "ec2:CreateSecurityGroup",
+                "ec2:ModifyInstanceAttribute",
+                "ec2:DescribeInstanceStatus"
+            ],
+            "Resource": "*"
+        },
+        {
+            "Effect": "Allow",
+            "Action": [
+                "iam:RemoveRoleFromInstanceProfile",
                 "iam:CreateRole",
-                "iam:CreateInstanceProfile",
-                "iam:CreatePolicy",
                 "iam:AttachRolePolicy",
+                "iam:PutRolePolicy",
                 "iam:AddRoleToInstanceProfile",
                 "iam:DetachRolePolicy",
-                "iam:DeleteInstanceProfile",
-                "iam:DeletePolicy",
-                "iam:DeleteRolePolicy",
-                "iam:DeleteRole",
-                "iam:RemoveRoleFromInstanceProfile",
-                "iam:GetRole",
-                "iam:GetRolePolicy",
-                "iam:GetInstanceProfile",
-                "iam:GetPolicy",
-                "iam:GetUser",
-                "iam:ListUsers",
-                "iam:ListAccessKeys",
-                "iam:PassRole",
-                "iam:ListUserPolicies",
-                "iam:PutRolePolicy",
-                "iam:ListInstanceProfiles",
                 "iam:ListAttachedRolePolicies",
-                "iam:ListInstanceProfilesForRole",
-                "iam:ListRoles",
-                "iam:ListPolicies",
                 "iam:ListRolePolicies",
-                "iam:TagRole"
+                "iam:ListPolicies",
+                "iam:GetRole",
+                "iam:GetPolicy",
+                "iam:DeleteRole",
+                "iam:GetRolePolicy",
+                "iam:CreateInstanceProfile",
+                "iam:TagRole",
+                "iam:DeletePolicy",
+                "iam:ListInstanceProfilesForRole",
+                "iam:PassRole",
+                "iam:DeleteRolePolicy",
+                "iam:ListAccessKeys",
+                "iam:DeleteInstanceProfile",
+                "iam:GetInstanceProfile",
+                "iam:ListRoles",
+                "iam:ListUserPolicies",
+                "iam:ListInstanceProfiles",
+                "iam:CreatePolicy",
+                "iam:ListUsers",
+                "iam:GetUser"
             ],
-            "Effect": "Allow",
             "Resource": "*"
         },
         {
-            "Action": [
-                "ec2:CreateVpcEndpoint",
-                "ec2:CreateSubnet",
-                "ec2:CreateTags",
-                "ec2:CreateImage",
-                "ec2:CreateRoute",
-                "ec2:DeregisterImage",
-                "ec2:DescribeImages",
-                "ec2:DescribeAddresses",
-                "ec2:AssociateAddress",
-                "ec2:DisassociateAddress",
-                "ec2:AllocateAddress",
-                "ec2:ReleaseAddress",
-                "ec2:CreateRouteTable",
-                "ec2:CreateSecurityGroup",
-                "ec2:AuthorizeSecurityGroupEgress",
-                "ec2:AuthorizeSecurityGroupIngress",
-                "ec2:AssociateRouteTable",
-                "ec2:DeleteRouteTable",
-                "ec2:DeleteSubnet",
-                "ec2:DeleteTags",
-                "ec2:DeleteSecurityGroup",
-                "ec2:DeleteSnapshot",
-                "ec2:DescribeRouteTables",
-                "ec2:DescribeSpotInstanceRequests",
-                "ec2:ModifyVpcEndpoint",
-                "ec2:RunInstances",
-                "ec2:StartInstances",
-                "ec2:StopInstances",
-                "ec2:TerminateInstances",
-                "ec2:DescribeSubnets",
-                "ec2:DescribeVpcs",
-                "ec2:DescribeSecurityGroups",
-                "ec2:DescribeInstances",
-                "ec2:DescribeInstanceStatus",
-                "ec2:ModifyInstanceAttribute",
-                "ec2:RevokeSecurityGroupEgress",
-                "ec2:RevokeSecurityGroupIngress",
-                "ec2:AuthorizeSecurityGroupEgress",
-                "ec2:AuthorizeSecurityGroupIngress"
-            ],
             "Effect": "Allow",
-            "Resource": "*"
-        },
-        {
             "Action": [
                 "s3:CreateBucket",
-                "s3:ListAllMyBuckets",
-                "s3:GetBucketLocation",
-                "s3:GetBucketTagging",
-                "s3:PutBucketTagging",
-                "s3:PutBucketPolicy",
-                "s3:GetBucketPolicy",
-                "s3:DeleteBucket",
                 "s3:DeleteObject",
-                "s3:GetObject",
-                "s3:ListBucket",
                 "s3:PutObject",
-                "s3:PutEncryptionConfiguration"
+                "s3:GetObject",
+                "s3:GetBucketTagging",
+                "s3:ListBucket",
+                "s3:GetBucketPolicy",
+                "s3:PutEncryptionConfiguration",
+                "s3:PutBucketTagging",
+                "s3:DeleteBucket",
+                "s3:ListAllMyBuckets",
+                "s3:PutBucketPolicy",
+                "s3:GetBucketLocation",
+                "s3:PutBucketPublicAccessBlock",
+                "s3:PutBucketVersioning",
+                "s3:ListBucketVersions",
+                "s3:DeleteObjectVersion",
+                "s3:DeleteObjectVersionTagging"
             ],
-            "Effect": "Allow",
             "Resource": "*"
         },
         {
+            "Effect": "Allow",
             "Action": [
-                "elasticmapreduce:AddTags",
-                "elasticmapreduce:RemoveTags",
+                "elasticmapreduce:ListInstances",
                 "elasticmapreduce:DescribeCluster",
                 "elasticmapreduce:ListClusters",
-                "elasticmapreduce:RunJobFlow",
-                "elasticmapreduce:ListInstances",
-                "elasticmapreduce:TerminateJobFlows"
+                "elasticmapreduce:TerminateJobFlows",
+                "elasticmapreduce:RemoveTags",
+                "elasticmapreduce:AddTags",
+                "elasticmapreduce:RunJobFlow"
             ],
-            "Effect": "Allow",
             "Resource": "*"
         },
         {
+            "Effect": "Allow",
             "Action": [
                 "pricing:GetProducts"
             ],
-            "Effect": "Allow",
             "Resource": "*"
         }
     ]
diff --git a/infrastructure-provisioning/src/general/files/aws/tensor-jupyterlab_Dockerfile b/infrastructure-provisioning/src/general/files/aws/tensor-jupyterlab_Dockerfile
new file mode 100644
index 0000000..c61ba5d
--- /dev/null
+++ b/infrastructure-provisioning/src/general/files/aws/tensor-jupyterlab_Dockerfile
@@ -0,0 +1,45 @@
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+
+FROM docker.datalab-base:latest
+
+ARG OS
+
+COPY tensor-jupyterlab/ /root/
+COPY general/scripts/os/* /root/scripts/
+COPY general/scripts/aws/tensor-jupyterlab_* /root/scripts/
+COPY general/lib/os/${OS}/notebook_lib.py /usr/lib/python3.8/datalab/notebook_lib.py
+COPY general/templates/os/${OS}/jupyterlab-notebook.service /root/templates/
+COPY general/templates/os/${OS}/ungit.service /root/templates/
+COPY general/templates/os/notebook_spark-defaults_local.conf /root/templates/
+COPY general/templates/os/pyspark_local_template.json /root/templates/
+COPY general/templates/os/py3spark_local_template.json /root/templates/
+COPY general/templates/os/pyspark_dataengine_template.json /root/templates/
+COPY general/templates/os/tensorboard.service /root/templates/
+COPY general/templates/os/pyspark_dataengine-service_template.json /root/templates/
+COPY general/templates/os/sparkmagic_config_template.json /root/templates/
+COPY general/templates/os/inactive.sh /root/templates/
+COPY general/templates/os/inactive.service /root/templates/
+COPY general/templates/os/inactive.timer /root/templates/
+
+RUN chmod a+x /root/fabfile.py; \
+    chmod a+x /root/scripts/*
diff --git a/infrastructure-provisioning/src/general/files/aws/tensor-jupyterlab_description.json b/infrastructure-provisioning/src/general/files/aws/tensor-jupyterlab_description.json
new file mode 100644
index 0000000..866bd38
--- /dev/null
+++ b/infrastructure-provisioning/src/general/files/aws/tensor-jupyterlab_description.json
@@ -0,0 +1,22 @@
+{
+  "exploratory_environment_shapes" :
+  {
+
+    "Memory optimized" : [
+      {"Size": "S", "Description": "r3.xlarge", "Type": "r3.xlarge","Ram": "30.5 GB","Cpu": "4"}
+    ],
+    "Compute optimized": [
+      {"Size": "S", "Description": "c4.large", "Type": "c4.large","Ram": "3.75 GB","Cpu": "2"}
+    ]
+  },
+  "exploratory_environment_versions" :
+  [
+    {
+      "template_name": "JupyterLab with TensorFlow 2.9.1",
+      "description": "Base image with TensorFlow and JupyterLab node creation routines",
+      "environment_type": "exploratory",
+      "version": "tensorflow-jupyterlab-2.9.1",
+      "vendor": "AWS"
+    }
+  ]
+}
diff --git a/infrastructure-provisioning/src/general/files/aws/tensor-rstudio_description.json b/infrastructure-provisioning/src/general/files/aws/tensor-rstudio_description.json
index 51fc3a4..4202f37 100644
--- a/infrastructure-provisioning/src/general/files/aws/tensor-rstudio_description.json
+++ b/infrastructure-provisioning/src/general/files/aws/tensor-rstudio_description.json
@@ -8,10 +8,10 @@
   "exploratory_environment_versions" :
   [
     {
-      "template_name": "RStudio with TensorFlow 2.5.0",
+      "template_name": "RStudio with TensorFlow 2.9.1",
       "description": "Base image with TensorFlow and RStudio node creation routines",
       "environment_type": "exploratory",
-      "version": "tensorflow_gpu-2.5.0",
+      "version": "tensorflow_gpu-2.9.1",
       "vendor": "AWS"
     }
   ]
diff --git a/infrastructure-provisioning/src/general/files/aws/tensor_description.json b/infrastructure-provisioning/src/general/files/aws/tensor_description.json
index 20402e6..c7c143c 100644
--- a/infrastructure-provisioning/src/general/files/aws/tensor_description.json
+++ b/infrastructure-provisioning/src/general/files/aws/tensor_description.json
@@ -8,10 +8,10 @@
   "exploratory_environment_versions" :
   [
     {
-      "template_name": "Jupyter with TensorFlow 2.5.0",
+      "template_name": "Jupyter with TensorFlow 2.9.1",
       "description": "Base image with TensorFlow and Jupyter node creation routines",
       "environment_type": "exploratory",
-      "version": "tensorflow_gpu-2.5.0",
+      "version": "tensorflow_gpu-2.9.1",
       "vendor": "AWS"
     }
   ]
diff --git a/infrastructure-provisioning/src/general/files/azure/base_Dockerfile b/infrastructure-provisioning/src/general/files/azure/base_Dockerfile
index fa6c516..03a97dd 100644
--- a/infrastructure-provisioning/src/general/files/azure/base_Dockerfile
+++ b/infrastructure-provisioning/src/general/files/azure/base_Dockerfile
@@ -26,12 +26,14 @@
 # Install any .deb dependecies
 RUN apt-get update && \
     apt-get -y upgrade && \
-    DEBIAN_FRONTEND=noninteractive apt-get -y install python3-pip python3-dev python3-virtualenv groff vim less git wget nano libssl-dev libffi-dev libffi7 && \
+    DEBIAN_FRONTEND=noninteractive apt-get -y install python3-pip python3-dev python3-virtualenv groff vim less git wget rsync nano libssl-dev libffi-dev libffi7 && \
     apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
 
 # Install any python dependencies
 RUN python3 -m pip install -UI qtconsole==5.1.1 pip==21.1.2 && \
-    python3 -m pip install backoff patchwork fabric fabvenv argparse requests ujson jupyter pycryptodome azure==2.0.0 azure-mgmt-authorization pyyaml
+    python3 -m pip install backoff patchwork fabric fabvenv argparse requests ujson jupyter pycryptodome azure-common pyyaml && \
+    python3 -m pip install azure-mgmt-storage azure-mgmt-compute azure-mgmt-core azure-mgmt-network azure-storage-blob azure-mgmt-resource && \
+    python3 -m pip install azure-storage-file-datalake azure-datalake-store azure-identity azure-mgmt-datalake-store azure-mgmt-hdinsight azure-common azure-core
 
 # Configuring ssh for user
 RUN mkdir -p /root/.ssh; echo "Host *" > /root/.ssh/config; \
diff --git a/infrastructure-provisioning/src/general/files/azure/dataengine-service_Dockerfile b/infrastructure-provisioning/src/general/files/azure/dataengine-service_Dockerfile
new file mode 100644
index 0000000..cd9ea3b
--- /dev/null
+++ b/infrastructure-provisioning/src/general/files/azure/dataengine-service_Dockerfile
@@ -0,0 +1,42 @@
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+FROM docker.datalab-base:latest
+
+ARG OS
+
+COPY dataengine-service/fabfile.py /root/
+COPY dataengine-service/description.json /root/
+COPY general/scripts/azure/dataengine-service_* /root/scripts/
+COPY general/lib/os/${OS}/notebook_lib.py /usr/lib/python3.8/datalab/notebook_lib.py
+COPY general/scripts/os/common_* /root/scripts/
+COPY general/scripts/os/install_additional_libs.py /root/scripts/install_additional_libs.py
+COPY general/scripts/os/get_list_available_pkgs.py /root/scripts/get_list_available_pkgs.py
+COPY general/templates/os/inactive.sh /root/templates/
+COPY general/templates/os/inactive.service /root/templates/
+COPY general/templates/os/inactive.timer /root/templates/
+COPY general/templates/azure/dataengine-service_interpreter_livy.json /root/templates/dataengine-service_interpreter_livy.json
+COPY general/templates/azure/dataengine-service_sparkmagic_config.json /root/templates/dataengine-service_sparkmagic_config.json
+
+
+RUN chmod a+x /root/fabfile.py; \
+    chmod a+x /root/scripts/*
+
diff --git a/infrastructure-provisioning/src/general/files/azure/dataengine-service_description.json b/infrastructure-provisioning/src/general/files/azure/dataengine-service_description.json
new file mode 100644
index 0000000..e2a5858
--- /dev/null
+++ b/infrastructure-provisioning/src/general/files/azure/dataengine-service_description.json
@@ -0,0 +1,20 @@
+{
+  "template_name": "HDInsight cluster",
+  "description": "HDInsight cluster",
+  "environment_type": "computational",
+  "computation_resources_shapes":
+    {
+      "For testing" : [
+        {"Size": "S", "Description": "Standard_D12_v2", "Type": "Standard_D12_v2","Ram": "28.0 GB","Cpu": "4"}
+      ],
+      "Memory optimized" : [
+        {"Size": "S", "Description": "Standard_E4_v3", "Type": "Standard_E4_v3","Ram": "32 GB","Cpu": "4"},
+        {"Size": "M", "Description": "Standard_E16_v3", "Type": "Standard_E16_v3","Ram": "128 GB","Cpu": "16"},
+        {"Size": "L", "Description": "Standard_E32_v3", "Type": "Standard_E32_v3","Ram": "256 GB","Cpu": "32"}
+      ]
+    },
+  "templates":
+  [
+    {"version":"5.0", "applications": [{"Name":"Spark", "Version": "3.1"}]}
+  ]
+}
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/general/files/azure/deeplearning_Dockerfile b/infrastructure-provisioning/src/general/files/azure/deeplearning_Dockerfile
index cf1c19e..b348d64 100644
--- a/infrastructure-provisioning/src/general/files/azure/deeplearning_Dockerfile
+++ b/infrastructure-provisioning/src/general/files/azure/deeplearning_Dockerfile
@@ -30,6 +30,7 @@
 COPY general/lib/os/${OS}/notebook_lib.py /usr/lib/python3.8/datalab/notebook_lib.py
 COPY general/templates/os/${OS}/jupyter-notebook.service /root/templates/
 COPY general/templates/os/${OS}/ungit.service /root/templates/
+COPY general/templates/os/${OS}/ungit.service.18_04 /root/templates/
 COPY general/templates/os/notebook_spark-defaults_local.conf /root/templates/
 COPY general/templates/os/pyspark_local_template.json /root/templates/
 COPY general/templates/os/py3spark_local_template.json /root/templates/
diff --git a/infrastructure-provisioning/src/general/files/azure/jupyter_Dockerfile b/infrastructure-provisioning/src/general/files/azure/jupyter_Dockerfile
index 4573684..18da125 100644
--- a/infrastructure-provisioning/src/general/files/azure/jupyter_Dockerfile
+++ b/infrastructure-provisioning/src/general/files/azure/jupyter_Dockerfile
@@ -45,6 +45,8 @@
 COPY general/templates/os/inactive.service /root/templates/
 COPY general/templates/os/inactive.timer /root/templates/
 COPY general/templates/azure/core-site* /root/templates/
+COPY general/templates/azure/dataengine-service_sparkmagic_config.json /root/templates/
+
 
 
 RUN chmod a+x /root/fabfile.py; \
diff --git a/infrastructure-provisioning/src/general/files/azure/jupyter_description.json b/infrastructure-provisioning/src/general/files/azure/jupyter_description.json
index 33ed451..cc9e9ce 100644
--- a/infrastructure-provisioning/src/general/files/azure/jupyter_description.json
+++ b/infrastructure-provisioning/src/general/files/azure/jupyter_description.json
@@ -15,10 +15,10 @@
   "exploratory_environment_versions" :
   [
     {
-      "template_name": "Jupyter notebook 6.1.6",
+      "template_name": "Jupyter 6.4.12",
       "description": "Base image with Jupyter node creation routines",
       "environment_type": "exploratory",
-      "version": "jupyter_notebook-6.1.6",
+      "version": "jupyter_notebook-6.4.12",
       "vendor": "Azure"
     }
   ]
diff --git a/infrastructure-provisioning/src/general/files/azure/jupyterlab_description.json b/infrastructure-provisioning/src/general/files/azure/jupyterlab_description.json
index 739bdcf..5783f96 100644
--- a/infrastructure-provisioning/src/general/files/azure/jupyterlab_description.json
+++ b/infrastructure-provisioning/src/general/files/azure/jupyterlab_description.json
@@ -15,10 +15,10 @@
   "exploratory_environment_versions" :
   [
     {
-      "template_name": "JupyterLab 0.35.6",
+      "template_name": "JupyterLab 3.4.3",
       "description": "Base image with JupyterLab node creation routines",
       "environment_type": "exploratory",
-      "version": "jupyter_lab-0.35.6",
+      "version": "jupyter_lab-3.4.3",
       "vendor": "Azure"
     }
   ]
diff --git a/infrastructure-provisioning/src/general/files/azure/rstudio_description.json b/infrastructure-provisioning/src/general/files/azure/rstudio_description.json
index 26d552a..6046bb1 100644
--- a/infrastructure-provisioning/src/general/files/azure/rstudio_description.json
+++ b/infrastructure-provisioning/src/general/files/azure/rstudio_description.json
@@ -15,10 +15,10 @@
   "exploratory_environment_versions" :
   [
     {
-      "template_name": "RStudio 2021.09.1-372",
+      "template_name": "RStudio 2022.02.2-485",
       "description": "Base image with RStudio node creation routines",
       "environment_type": "exploratory",
-      "version": "RStudio-2021.09.1-372",
+      "version": "RStudio-2022.02.2-485",
       "vendor": "Azure"
     }
   ]
diff --git a/infrastructure-provisioning/src/general/files/azure/tensor_description.json b/infrastructure-provisioning/src/general/files/azure/tensor_description.json
index 3a89e60..da31718 100644
--- a/infrastructure-provisioning/src/general/files/azure/tensor_description.json
+++ b/infrastructure-provisioning/src/general/files/azure/tensor_description.json
@@ -8,10 +8,10 @@
   "exploratory_environment_versions" :
   [
     {
-      "template_name": "Jupyter with TensorFlow 2.5.0",
+      "template_name": "Jupyter with TensorFlow 2.9.1",
       "description": "Base image with TensorFlow and Jupyter node creation routines",
       "environment_type": "exploratory",
-      "version": "tensorflow_gpu-2.5.0",
+      "version": "tensorflow_gpu-2.9.1",
       "vendor": "Azure"
     }
   ]
diff --git a/infrastructure-provisioning/src/general/files/azure/zeppelin_Dockerfile b/infrastructure-provisioning/src/general/files/azure/zeppelin_Dockerfile
index b2a0a6f..46f01d1 100644
--- a/infrastructure-provisioning/src/general/files/azure/zeppelin_Dockerfile
+++ b/infrastructure-provisioning/src/general/files/azure/zeppelin_Dockerfile
@@ -28,6 +28,7 @@
 COPY general/scripts/os/* /root/scripts/
 COPY general/scripts/azure/zeppelin_* /root/scripts/
 COPY general/lib/os/${OS}/notebook_lib.py /usr/lib/python3.8/datalab/notebook_lib.py
+COPY general/templates/azure/dataengine-service_interpreter_livy.json /root/templates/
 COPY general/templates/azure/interpreter_livy.json /root/templates/
 COPY general/templates/azure/interpreter_spark.json /root/templates/
 COPY general/templates/os/dataengine_interpreter_livy.json /root/templates/
diff --git a/infrastructure-provisioning/src/general/files/gcp/base_Dockerfile b/infrastructure-provisioning/src/general/files/gcp/base_Dockerfile
index 4d6d4b2..2be04ba 100644
--- a/infrastructure-provisioning/src/general/files/gcp/base_Dockerfile
+++ b/infrastructure-provisioning/src/general/files/gcp/base_Dockerfile
@@ -26,7 +26,7 @@
 # Install any .deb dependecies
 RUN	apt-get update && \
     apt-get -y upgrade && \
-    DEBIAN_FRONTEND=noninteractive apt-get -y install python3-pip python3-dev python3-virtualenv groff vim less git wget nano libssl-dev libffi-dev libffi7 && \
+    DEBIAN_FRONTEND=noninteractive apt-get -y install python3-pip python3-dev python3-virtualenv groff vim less git wget rsync nano libssl-dev libffi-dev libffi7 && \
     apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
 
 # To cahnge POSIX locale to en_US.UTF-8
diff --git a/infrastructure-provisioning/src/general/files/gcp/dataengine-service_description.json b/infrastructure-provisioning/src/general/files/gcp/dataengine-service_description.json
index ba9da13..1c48526 100644
--- a/infrastructure-provisioning/src/general/files/gcp/dataengine-service_description.json
+++ b/infrastructure-provisioning/src/general/files/gcp/dataengine-service_description.json
@@ -25,6 +25,6 @@
   },
   "templates":
   [
-    {"version":"2.0.0-RC22-ubuntu18", "applications": [{"Name":"Hadoop", "Version": "3.2.2"}, {"Name":"Spark", "Version": "3.1.1"}, {"Name":"Hive", "Version": "3.1.2"}]}
+    {"version":"2.0.27-ubuntu18", "applications": [{"Name":"Hadoop", "Version": "3.2.2"}, {"Name":"Spark", "Version": "3.1.1"}, {"Name":"Hive", "Version": "3.1.2"}]}
   ]
 }
diff --git a/infrastructure-provisioning/src/general/files/gcp/jupyter-gpu_Dockerfile b/infrastructure-provisioning/src/general/files/gcp/jupyter-gpu_Dockerfile
new file mode 100644
index 0000000..87c4114
--- /dev/null
+++ b/infrastructure-provisioning/src/general/files/gcp/jupyter-gpu_Dockerfile
@@ -0,0 +1,54 @@
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+
+FROM docker.datalab-base:latest
+
+ARG OS
+
+COPY jupyter-gpu/ /root/
+COPY general/scripts/os/* /root/scripts/
+COPY general/scripts/gcp/jupyter-gpu_* /root/scripts/
+COPY general/lib/os/${OS}/notebook_lib.py /usr/lib/python3.8/datalab/notebook_lib.py
+COPY general/templates/os/${OS}/jupyter-notebook.service /root/templates/
+COPY general/templates/os/${OS}/ungit.service /root/templates/
+COPY general/templates/os/notebook_spark-defaults_local.conf /root/templates/
+COPY general/templates/os/pyspark_local_template.json /root/templates/
+COPY general/templates/os/py3spark_local_template.json /root/templates/
+COPY general/templates/os/pyspark_dataengine-service_template.json /root/templates/
+COPY general/templates/os/sparkmagic_config_template.json /root/templates/
+COPY general/templates/os/r_dataengine-service_template.json /root/templates/
+COPY general/templates/os/r_template.json /root/templates/
+COPY general/templates/os/run_template.sh /root/templates/
+COPY general/templates/os/toree_dataengine-service_* /root/templates/
+COPY general/templates/os/inactive.sh /root/templates/
+COPY general/templates/os/inactive.service /root/templates/
+COPY general/templates/os/inactive.timer /root/templates/
+COPY general/files/os/toree-assembly-0.5.0.jar /root/files/
+COPY general/files/os/toree_kernel.tar.gz /root/files/
+COPY general/templates/os/pyspark_dataengine_template.json /root/templates/
+COPY general/templates/os/r_dataengine_template.json /root/templates/
+COPY general/templates/os/toree_dataengine_template.json /root/templates/
+COPY general/templates/gcp/core-site.xml /root/templates/
+
+RUN chmod a+x /root/fabfile.py; \
+    chmod a+x /root/scripts/*
+
diff --git a/infrastructure-provisioning/src/general/files/gcp/jupyter-gpu_description.json b/infrastructure-provisioning/src/general/files/gcp/jupyter-gpu_description.json
new file mode 100644
index 0000000..685db26
--- /dev/null
+++ b/infrastructure-provisioning/src/general/files/gcp/jupyter-gpu_description.json
@@ -0,0 +1,18 @@
+{
+  "exploratory_environment_shapes" :
+  {
+    "GPU" : [
+      {"Size": "S", "Description": "a2-highgpu-1g", "Type": "a2-highgpu-1g","Ram": "85 GB","Cpu": "12"}
+    ]
+  },
+  "exploratory_environment_versions" :
+  [
+    {
+      "template_name": "Jupyter 6.4.12 with GPU",
+      "description": "Base image with jupyter node creation routines",
+      "environment_type": "exploratory",
+      "version": "jupyter_notebook_gpu",
+      "vendor": "GCP"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/general/files/gcp/jupyter_description.json b/infrastructure-provisioning/src/general/files/gcp/jupyter_description.json
index 1eafbed..4a1f52d 100644
--- a/infrastructure-provisioning/src/general/files/gcp/jupyter_description.json
+++ b/infrastructure-provisioning/src/general/files/gcp/jupyter_description.json
@@ -23,10 +23,10 @@
   "exploratory_environment_versions" :
   [
     {
-      "template_name": "Jupyter notebook 6.1.6",
+      "template_name": "Jupyter 6.4.12",
       "description": "Base image with jupyter node creation routines",
       "environment_type": "exploratory",
-      "version": "jupyter_notebook-6.1.6",
+      "version": "jupyter_notebook-6.4.12",
       "vendor": "GCP"
     }
   ]
diff --git a/infrastructure-provisioning/src/general/files/gcp/jupyterlab_description.json b/infrastructure-provisioning/src/general/files/gcp/jupyterlab_description.json
index 3f202f7..6f69793 100644
--- a/infrastructure-provisioning/src/general/files/gcp/jupyterlab_description.json
+++ b/infrastructure-provisioning/src/general/files/gcp/jupyterlab_description.json
@@ -23,10 +23,10 @@
   "exploratory_environment_versions" :
   [
     {
-      "template_name": "JupyterLab 0.35.6",
+      "template_name": "JupyterLab 3.4.3",
       "description": "Base image with JupyterLab node creation routines",
       "environment_type": "exploratory",
-      "version": "jupyter_lab-0.35.6",
+      "version": "jupyter_lab-3.4.3",
       "vendor": "GCP"
     }
   ]
diff --git a/infrastructure-provisioning/src/general/files/gcp/rstudio_description.json b/infrastructure-provisioning/src/general/files/gcp/rstudio_description.json
index 13be8d7..9ae7efa 100644
--- a/infrastructure-provisioning/src/general/files/gcp/rstudio_description.json
+++ b/infrastructure-provisioning/src/general/files/gcp/rstudio_description.json
@@ -23,10 +23,10 @@
   "exploratory_environment_versions" :
   [
     {
-      "template_name": "RStudio 2021.09.1-372",
+      "template_name": "RStudio 2022.02.2-485",
       "description": "Base image with rstudio node creation routines",
       "environment_type": "exploratory",
-      "version": "RStudio-2021.09.1-372",
+      "version": "RStudio-2022.02.2-485",
       "vendor": "GCP"
     }
   ]
diff --git a/infrastructure-provisioning/src/general/files/gcp/superset_description.json b/infrastructure-provisioning/src/general/files/gcp/superset_description.json
index 98f394f..166a0fa 100644
--- a/infrastructure-provisioning/src/general/files/gcp/superset_description.json
+++ b/infrastructure-provisioning/src/general/files/gcp/superset_description.json
@@ -18,7 +18,7 @@
   "exploratory_environment_versions" :
   [
     {
-      "template_name": "Superset 0.35.1",
+      "template_name": "Superset 1.5.1",
       "description": "Base image with superset node creation routines",
       "environment_type": "exploratory",
       "version": "superset-0.34",
diff --git a/infrastructure-provisioning/src/general/files/gcp/tensor_description.json b/infrastructure-provisioning/src/general/files/gcp/tensor_description.json
index 8561110..f335123 100644
--- a/infrastructure-provisioning/src/general/files/gcp/tensor_description.json
+++ b/infrastructure-provisioning/src/general/files/gcp/tensor_description.json
@@ -10,10 +10,10 @@
   "exploratory_environment_versions" :
   [
     {
-      "template_name": "Jupyter with TensorFlow 2.5.0",
+      "template_name": "Jupyter with TensorFlow 2.9.1",
       "description": "Base image with TensorFlow and Jupyter node creation routines",
       "environment_type": "exploratory",
-      "version": "tensorflow_gpu-2.5.0",
+      "version": "tensorflow_gpu-2.9.1",
       "vendor": "GCP"
     }
   ]
diff --git a/infrastructure-provisioning/src/general/lib/aws/actions_lib.py b/infrastructure-provisioning/src/general/lib/aws/actions_lib.py
index 567c3b6..33ef6c6 100644
--- a/infrastructure-provisioning/src/general/lib/aws/actions_lib.py
+++ b/infrastructure-provisioning/src/general/lib/aws/actions_lib.py
@@ -65,13 +65,18 @@
         return False
 
 
-def create_s3_bucket(bucket_name, bucket_tags, region, bucket_name_tag):
+def create_s3_bucket(bucket_name, bucket_tags, region, bucket_name_tag, bucket_versioning_enabled):
     try:
         s3 = boto3.resource('s3', config=botoConfig(signature_version='s3v4'))
         if region == "us-east-1":
             bucket = s3.create_bucket(Bucket=bucket_name)
         else:
             bucket = s3.create_bucket(Bucket=bucket_name, CreateBucketConfiguration={'LocationConstraint': region})
+
+        if bucket_versioning_enabled == "true":
+            bucket_versioning = s3.BucketVersioning(bucket_name)
+            bucket_versioning.enable()
+
         boto3.client('s3', config=botoConfig(signature_version='s3v4')).put_bucket_encryption(
             Bucket=bucket_name, ServerSideEncryptionConfiguration={
                 'Rules': [
@@ -82,6 +87,43 @@
                     },
                 ]
             })
+
+        # Config for Public Access Block in s3
+        boto3.client('s3', config=botoConfig(signature_version='s3v4')).put_public_access_block(
+            Bucket=bucket_name,
+            PublicAccessBlockConfiguration={
+                'BlockPublicAcls': True,
+                'IgnorePublicAcls': True,
+                'BlockPublicPolicy': True,
+                'RestrictPublicBuckets': True
+            })
+
+        # Configuring bucket policy to ensure encryption in transit
+        bucket_policy = {
+            "Version": "2012-10-17",
+            "Statement": [
+                {
+                    "Effect": "Deny",
+                    "Principal": {"AWS": "*"},
+                    "Action": "s3:*",
+                    "Resource": [
+                        f"arn:aws:s3:::{bucket_name}",
+                        f"arn:aws:s3:::{bucket_name}/*"
+                    ],
+                    "Condition": {
+                        "Bool": {"aws:SecureTransport": "false"}
+                    }
+                }]
+        }
+
+        # Convert the policy from Json dict to string
+        bucket_policy = json.dumps(bucket_policy)
+
+        boto3.client('s3', config=botoConfig(signature_version='s3v4')).put_bucket_policy(
+            Bucket=bucket_name,
+            Policy=bucket_policy
+        )
+
         tags = list()
         tags.append({'Key': os.environ['conf_tag_resource_id'],
                      'Value': os.environ['conf_service_base_name'] + ':' + bucket_name_tag})
@@ -1101,7 +1143,7 @@
         for s3bucket in bucket_list:
             if s3bucket:
                 bucket = s3.Bucket(s3bucket)
-                bucket.objects.all().delete()
+                bucket.object_versions.delete()
                 print("The S3 bucket {} has been cleaned".format(s3bucket))
                 client.delete_bucket(Bucket=s3bucket)
                 print("The S3 bucket {} has been deleted successfully".format(s3bucket))
@@ -1455,6 +1497,7 @@
             print("The checksum of spark.tar.gz is mismatched. It could be caused by aws network issue.")
             sys.exit(1)
     subprocess.run('sudo tar -zhxvf /tmp/spark.tar.gz -C /opt/' + args.emr_version + '/' + args.cluster_name + '/', shell=True, check=True)
+    subprocess.run('sudo cp -R /opt/spark/R/lib/SparkR /opt/' + args.emr_version + '/' + args.cluster_name + '/spark/R/lib/', shell=True, check=True)
 
 
 def jars(args, emr_dir):
@@ -1539,7 +1582,8 @@
         sys.exit(1)
 
 
-def installing_python(region, bucket, user_name, cluster_name, application='', pip_mirror='', numpy_version='1.14.3'):
+def installing_python(region, bucket, user_name, cluster_name, application='', numpy_version='1.14.3',
+                      matplotlib_version='3.3.4', pip_mirror=''):
     get_cluster_python_version(region, bucket, user_name, cluster_name)
     with open('/tmp/python_version') as f:
         python_version = f.read()
@@ -1548,7 +1592,8 @@
         subprocess.run('wget https://www.python.org/ftp/python/' + python_version +
               '/Python-' + python_version + '.tgz -O /tmp/Python-' + python_version + '.tgz', shell=True, check=True)
         subprocess.run('tar zxvf /tmp/Python-' + python_version + '.tgz -C /tmp/', shell=True, check=True)
-        subprocess.run('cd /tmp/Python-{0}; ./configure --prefix=/opt/python/python{0} --with-zlib-dir=/usr/local/lib/ --with-ensurepip=install'.format(python_version), shell=True, check=True)
+        subprocess.run('cd /tmp/Python-{0}; ./configure --prefix=/opt/python/python{0} --with-zlib-dir=/usr/local/lib/ '
+                       '--with-ensurepip=install'.format(python_version), shell=True, check=True)
         subprocess.run('cd /tmp/Python-{0}; sudo make altinstall'.format(python_version), shell=True, check=True)
         subprocess.run('cd /tmp/; sudo rm -rf Python-' + python_version + '/', shell=True, check=True)
         if region == 'cn-north-1':
@@ -1559,8 +1604,8 @@
             subprocess.run('sudo echo "[global]" >> /etc/pip.conf', shell=True, check=True)
             subprocess.run('sudo echo "timeout = 600" >> /etc/pip.conf', shell=True, check=True)
         subprocess.run('sudo -i virtualenv /opt/python/python' + python_version, shell=True, check=True)
-        venv_command = '/bin/bash /opt/python/python' + python_version + '/bin/activate'
-        pip_command = '/opt/python/python' + python_version + '/bin/pip' + python_version[:3]
+        venv_command = 'source /opt/python/python{}/bin/activate'.format(python_version)
+        pip_command = '/opt/python/python{0}/bin/pip{1}'.format(python_version, python_version[:3])
         if region == 'cn-north-1':
             try:
                 subprocess.run(venv_command + ' && sudo -i ' + pip_command +
@@ -1573,7 +1618,7 @@
                 subprocess.run(venv_command + ' && sudo -i ' + pip_command + ' install NumPy=={0}'.format(numpy_version), shell=True, check=True)
                 subprocess.run(venv_command + ' && sudo -i ' + pip_command +
                       ' install -i https://{0}/simple --trusted-host {0} --timeout 60000 boto boto3 SciPy '
-                      'Matplotlib=={1} pandas Sympy Pillow sklearn --no-cache-dir'.format(pip_mirror, os.environ['notebook_matplotlib_version']), shell=True, check=True)
+                      'Matplotlib=={1} pandas Sympy Pillow sklearn --no-cache-dir'.format(pip_mirror, matplotlib_version), shell=True, check=True)
                 # Need to refactor when we add GPU cluster
                 if application == 'deeplearning':
                     subprocess.run(venv_command + ' && sudo -i ' + pip_command +
@@ -1591,24 +1636,23 @@
                 subprocess.run('sudo rm -rf /opt/python/python{}/'.format(python_version), shell=True, check=True)
                 sys.exit(1)
         else:
-            print(subprocess.run(venv_command + ' && sudo -i ' + pip_command + ' install -U pip==9.0.3', shell=True, check=True))
-            subprocess.run(venv_command + ' && sudo -i ' + pip_command + ' install pyzmq==17.0.0', shell=True, check=True)
-            subprocess.run(venv_command + ' && sudo -i ' + pip_command + ' install ipython ipykernel --no-cache-dir', shell=True, check=True)
-            subprocess.run(venv_command + ' && sudo -i ' + pip_command + ' install NumPy=={}'.format(numpy_version), shell=True, check=True)
-            subprocess.run(venv_command + ' && sudo -i ' + pip_command +
-                  ' install boto boto3 SciPy Matplotlib=={} pandas Sympy Pillow sklearn '
-                  '--no-cache-dir'.format(os.environ['notebook_matplotlib_version']), shell=True, check=True)
+            for lib in ['-U pip==9.0.3', 'pyzmq==17.0.0',
+                        'ipython ipykernel boto boto3 pybind11 pythran cython NumPy=={0} Matplotlib=={1} '
+                        '--no-cache-dir'.format(numpy_version, matplotlib_version),
+                        'SciPy pandas Sympy Pillow', 'sklearn --no-cache-dir']:
+                subprocess.run('bash -c "{0} && sudo -i {1} install {2}"'
+                               .format(venv_command, pip_command, lib), shell=True, check=True)
             # Need to refactor when we add GPU cluster
             if application == 'deeplearning':
-                subprocess.run(venv_command + ' && sudo -i ' + pip_command +
-                      ' install mxnet-cu80 opencv-python keras Theano --no-cache-dir', shell=True, check=True)
+                subprocess.run('bash -c "{0} && sudo -i {1} install mxnet-cu80 opencv-python keras Theano '
+                               '--no-cache-dir"'.format(venv_command, pip_command), shell=True, check=True)
                 python_without_dots = python_version.replace('.', '')
-                subprocess.run(venv_command + ' && sudo -i ' + pip_command +
-                      ' install  https://cntk.ai/PythonWheel/GPU/cntk-2.0rc3-cp{0}-cp{0}m-linux_x86_64.whl '
-                      '--no-cache-dir'.format(python_without_dots[:2]), shell=True, check=True)
+                subprocess.run('bash -c "{0} && sudo -i {1} install https://cntk.ai/PythonWheel/GPU/cntk-2.0rc3-cp{0}'
+                               '-cp{0}m-linux_x86_64.whl --no-cache-dir"'
+                               .format(venv_command, pip_command, python_without_dots[:2]), shell=True, check=True)
         subprocess.run('sudo rm -rf /usr/bin/python{}-dp'.format(python_version[0:3]), shell=True, check=True)
-        subprocess.run('sudo ln -fs /opt/python/python{0}/bin/python{1} /usr/bin/python{1}-dp'.format(python_version,
-                                                                                             python_version[0:3]), shell=True, check=True)
+        subprocess.run('sudo ln -fs /opt/python/python{0}/bin/python{1} /usr/bin/python{1}-dp'
+                       .format(python_version, python_version[0:3]), shell=True, check=True)
 
 
 def spark_defaults(args):
@@ -1645,9 +1689,11 @@
         try:
             datalab.fab.conn.sudo('mkdir -p {0}'.format(jars_dir))
             datalab.fab.conn.sudo('wget https://repo1.maven.org/maven2/org/apache/hadoop/hadoop-aws/{0}/hadoop-aws-{0}.jar -O \
-                    {1}hadoop-aws-{0}.jar'.format('2.7.4', jars_dir))
+                    {1}hadoop-aws-{0}.jar'.format('3.2.0', jars_dir))
             datalab.fab.conn.sudo('wget https://repo1.maven.org/maven2/com/amazonaws/aws-java-sdk/{0}/aws-java-sdk-{0}.jar -O \
-                    {1}aws-java-sdk-{0}.jar'.format('1.7.4', jars_dir))
+                    {1}aws-java-sdk-{0}.jar'.format('1.11.874', jars_dir))
+            datalab.fab.conn.sudo('wget https://repo1.maven.org/maven2/com/amazonaws/aws-java-sdk-bundle/{0}/aws-java-sdk-bundle-{0}.jar -O \
+                    {1}aws-java-sdk-bundle-{0}.jar'.format('1.11.874', jars_dir))
             # datalab.fab.conn.sudo('wget https://maven.twttr.com/com/hadoop/gplcompression/hadoop-lzo/{0}/hadoop-lzo-{0}.jar -O \
             #         {1}hadoop-lzo-{0}.jar'.format('0.4.20', jars_dir))
             datalab.fab.conn.sudo('touch /home/{}/.ensure_dir/local_jars_ensured'.format(os_user))
@@ -1676,8 +1722,6 @@
             endpoint_url))
         datalab.fab.conn.sudo('echo "spark.hadoop.fs.s3a.server-side-encryption-algorithm   AES256" >> '
              '/tmp/notebook_spark-defaults_local.conf')
-        if not exists(datalab.fab.conn,'/opt/spark/conf/spark-env.sh'):
-            datalab.fab.conn.sudo('mv /opt/spark/conf/spark-env.sh.template /opt/spark/conf/spark-env.sh')
         java_home = datalab.fab.conn.run("update-alternatives --query java | grep -o --color=never \'/.*/java-8.*/jre\'").stdout.splitlines()[0].replace('\n','')
         datalab.fab.conn.sudo("echo 'export JAVA_HOME=\'{}\'' >> /opt/spark/conf/spark-env.sh".format(java_home))
         if os.environ['application'] == 'zeppelin':
@@ -1960,6 +2004,8 @@
 def ensure_local_spark(os_user, spark_link, spark_version, hadoop_version, local_spark_path):
     if not exists(datalab.fab.conn,'/home/' + os_user + '/.ensure_dir/local_spark_ensured'):
         try:
+ #           spark_version = '3.2.0'
+ #           hadoop_version = '3.2'
             datalab.fab.conn.sudo('wget ' + spark_link + ' -O /tmp/spark-' + spark_version + '-bin-hadoop' + hadoop_version + '.tgz')
             datalab.fab.conn.sudo('tar -zxvf /tmp/spark-' + spark_version + '-bin-hadoop' + hadoop_version + '.tgz -C /opt/')
             datalab.fab.conn.sudo('mv /opt/spark-' + spark_version + '-bin-hadoop' + hadoop_version + ' ' + local_spark_path)
diff --git a/infrastructure-provisioning/src/general/lib/aws/meta_lib.py b/infrastructure-provisioning/src/general/lib/aws/meta_lib.py
index 063b215..e3749d8 100644
--- a/infrastructure-provisioning/src/general/lib/aws/meta_lib.py
+++ b/infrastructure-provisioning/src/general/lib/aws/meta_lib.py
@@ -747,9 +747,33 @@
                         host['status'] = j.get('State').get('Name')
                         data.append(host)
         except Exception as err:
-            host['id'] = i.get('id')
+            host['id'] = h.get('id')
             host['status'] = 'terminated'
-            host['error_response'] = err
+            #host['error_response'] = err
+            data.append(host)
+    return data
+
+
+def get_list_image_statuses(image_ids, data=[]):
+    client = boto3.client('ec2')
+    for k in image_ids:
+        host = {}
+        try:
+            response = client.describe_images(ImageIds=[k.get('id')]).get('Images')
+            for i in response:
+                host['id'] = i.get('ImageId')
+                if i.get('State') == 'pending':
+                    host['status'] = 'CREATING'
+                elif i.get('State') == 'available':
+                    host['status'] = 'ACTIVE'
+                elif i.get('State') == 'invalid' or i.get('State') == 'error' or i.get('State') == 'failed':
+                    host['status'] = 'FAILED'
+                elif i.get('State') == 'deregistered':
+                    host['status'] = 'TERMINATED'
+                data.append(host)
+        except Exception as err:
+            host['id'] = k.get('id')
+            host['status'] = 'TERMINATED'
             data.append(host)
     return data
 
diff --git a/infrastructure-provisioning/src/general/lib/azure/actions_lib.py b/infrastructure-provisioning/src/general/lib/azure/actions_lib.py
index 09ec650..d5fc547 100644
--- a/infrastructure-provisioning/src/general/lib/azure/actions_lib.py
+++ b/infrastructure-provisioning/src/general/lib/azure/actions_lib.py
@@ -34,15 +34,15 @@
 import urllib3
 import urllib.request
 import subprocess
-from azure.common.client_factory import get_client_from_auth_file
 from azure.datalake.store import core, lib
-from azure.mgmt.authorization import AuthorizationManagementClient
 from azure.mgmt.compute import ComputeManagementClient
-from azure.mgmt.datalake.store import DataLakeStoreAccountManagementClient
 from azure.mgmt.network import NetworkManagementClient
 from azure.mgmt.resource import ResourceManagementClient
 from azure.mgmt.storage import StorageManagementClient
-from azure.storage.blob import BlockBlobService
+from azure.storage.blob import BlobServiceClient
+from azure.identity import ClientSecretCredential
+from azure.mgmt.datalake.store import DataLakeStoreAccountManagementClient
+from azure.mgmt.hdinsight import HDInsightManagementClient
 from fabric import *
 from patchwork.files import exists
 from patchwork import files
@@ -51,17 +51,57 @@
 class AzureActions:
     def __init__(self):
         os.environ['AZURE_AUTH_LOCATION'] = '/root/azure_auth.json'
-        self.compute_client = get_client_from_auth_file(ComputeManagementClient)
-        self.resource_client = get_client_from_auth_file(ResourceManagementClient)
-        self.network_client = get_client_from_auth_file(NetworkManagementClient)
-        self.storage_client = get_client_from_auth_file(StorageManagementClient)
-        self.datalake_client = get_client_from_auth_file(DataLakeStoreAccountManagementClient)
-        #self.authorization_client = get_client_from_auth_file(AuthorizationManagementClient)
+        with open('/root/azure_auth.json') as json_file:
+            json_dict = json.load(json_file)
+
+        self.credential = ClientSecretCredential(
+            tenant_id=json_dict["tenantId"],
+            client_id=json_dict["clientId"],
+            client_secret=json_dict["clientSecret"],
+            authority=json_dict["activeDirectoryEndpointUrl"]
+        )
+
+        self.compute_client = ComputeManagementClient(
+            self.credential,
+            json_dict["subscriptionId"],
+            base_url=json_dict["resourceManagerEndpointUrl"],
+            credential_scopes=["{}/.default".format(json_dict["resourceManagerEndpointUrl"])]
+        )
+        self.resource_client = ResourceManagementClient(
+            self.credential,
+            json_dict["subscriptionId"],
+            base_url=json_dict["resourceManagerEndpointUrl"],
+            credential_scopes=["{}/.default".format(json_dict["resourceManagerEndpointUrl"])]
+        )
+        self.network_client = NetworkManagementClient(
+            self.credential,
+            json_dict["subscriptionId"],
+            base_url=json_dict["resourceManagerEndpointUrl"],
+            credential_scopes=["{}/.default".format(json_dict["resourceManagerEndpointUrl"])]
+        )
+        self.storage_client = StorageManagementClient(
+            self.credential,
+            json_dict["subscriptionId"],
+            base_url=json_dict["resourceManagerEndpointUrl"],
+            credential_scopes=["{}/.default".format(json_dict["resourceManagerEndpointUrl"])]
+        )
+        self.datalake_client = DataLakeStoreAccountManagementClient(
+            self.credential,
+            json_dict["subscriptionId"],
+            base_url=json_dict["resourceManagerEndpointUrl"]
+        )
+        self.hdinsight_client = HDInsightManagementClient(
+            self.credential,
+            json_dict["subscriptionId"],
+            base_url=json_dict["resourceManagerEndpointUrl"]
+        )
         self.sp_creds = json.loads(open(os.environ['AZURE_AUTH_LOCATION']).read())
         self.dl_filesystem_creds = lib.auth(tenant_id=json.dumps(self.sp_creds['tenantId']).replace('"', ''),
                                             client_secret=json.dumps(self.sp_creds['clientSecret']).replace('"', ''),
                                             client_id=json.dumps(self.sp_creds['clientId']).replace('"', ''),
                                             resource='https://datalake.azure.net/')
+        logger = logging.getLogger('azure')
+        logger.setLevel(logging.ERROR)
 
     def create_resource_group(self, resource_group_name, region):
         try:
@@ -77,7 +117,8 @@
             return result
         except Exception as err:
             logging.info(
-                "Unable to create Resource Group: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to create Resource Group: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to create Resource Group",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
@@ -85,7 +126,7 @@
 
     def remove_resource_group(self, resource_group_name, region):
         try:
-            result = self.resource_client.resource_groups.delete(
+            result = self.resource_client.resource_groups.begin_delete(
                 resource_group_name,
                 {
                     'location': region
@@ -94,7 +135,8 @@
             return result
         except Exception as err:
             logging.info(
-                "Unable to remove Resource Group: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to remove Resource Group: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to remove Resource Group",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
@@ -102,7 +144,7 @@
 
     def create_vpc(self, resource_group_name, vpc_name, region, vpc_cidr):
         try:
-            result = self.network_client.virtual_networks.create_or_update(
+            result = self.network_client.virtual_networks.begin_create_or_update(
                 resource_group_name,
                 vpc_name,
                 {
@@ -113,13 +155,27 @@
                     },
                     'address_space': {
                         'address_prefixes': [vpc_cidr]
-                    }
+                    },
+                    "subnets": [
+                        {
+                            "name": os.environ['azure_subnet_name'],
+                            "service_endpoints": [
+                                {
+                                    "service": "Microsoft.Storage",
+                                    "locations": [
+                                        region
+                                    ]
+                                }
+                            ]
+                        }
+                    ]
                 }
             )
             return result
         except Exception as err:
             logging.info(
-                "Unable to create Virtual Network: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to create Virtual Network: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to create Virtual Network",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
@@ -146,7 +202,8 @@
             return result
         except Exception as err:
             logging.info(
-                "Unable to create Virtual Network peering: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to create Virtual Network peering: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to create Virtual Network peering",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
@@ -154,14 +211,15 @@
 
     def remove_vpc(self, resource_group_name, vpc_name):
         try:
-            result = self.network_client.virtual_networks.delete(
+            result = self.network_client.virtual_networks.begin_delete(
                 resource_group_name,
                 vpc_name
             )
             return result
         except Exception as err:
             logging.info(
-                "Unable to remove Virtual Network: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to remove Virtual Network: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to remove Virtual Network",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
@@ -169,12 +227,21 @@
 
     def create_subnet(self, resource_group_name, vpc_name, subnet_name, subnet_cidr):
         try:
-            result = self.network_client.subnets.create_or_update(
+            region = os.environ['azure_region']
+            result = self.network_client.subnets.begin_create_or_update(
                 resource_group_name,
                 vpc_name,
                 subnet_name,
                 {
-                    'address_prefix': subnet_cidr
+                    "address_prefix": subnet_cidr,
+                    "service_endpoints": [
+                        {
+                            "service": "Microsoft.Storage",
+                            "locations": [
+                                region
+                            ]
+                        }
+                    ]
                 }
             )
             return result
@@ -188,7 +255,7 @@
 
     def remove_subnet(self, resource_group_name, vpc_name, subnet_name):
         try:
-            result = self.network_client.subnets.delete(
+            result = self.network_client.subnets.begin_delete(
                 resource_group_name,
                 vpc_name,
                 subnet_name
@@ -202,11 +269,12 @@
                                    file=sys.stdout)}))
             traceback.print_exc(file=sys.stdout)
 
-    def create_security_group(self, resource_group_name, network_security_group_name, region, tags, list_rules, preexisting_sg = False):
+    def create_security_group(self, resource_group_name, network_security_group_name, region, tags, list_rules,
+                              preexisting_sg=False):
         try:
             result = ''
             if not preexisting_sg:
-                result = self.network_client.network_security_groups.create_or_update(
+                result = self.network_client.network_security_groups.begin_create_or_update(
                     resource_group_name,
                     network_security_group_name,
                     {
@@ -215,7 +283,7 @@
                     }
                 ).wait()
             for rule in list_rules:
-                self.network_client.security_rules.create_or_update(
+                self.network_client.security_rules.begin_create_or_update(
                     resource_group_name,
                     network_security_group_name,
                     security_rule_name=rule['name'],
@@ -225,7 +293,8 @@
                 return result
         except Exception as err:
             logging.info(
-                "Unable to create security group: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to create security group: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to create security group",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
@@ -233,10 +302,10 @@
 
     def remove_security_rules(self, network_security_group, resource_group, security_rule):
         try:
-            result = self.network_client.security_rules.delete(
-                network_security_group_name = network_security_group,
-                resource_group_name = resource_group,
-                security_rule_name = security_rule).wait()
+            result = self.network_client.security_rules.begin_delete(
+                network_security_group_name=network_security_group,
+                resource_group_name=resource_group,
+                security_rule_name=security_rule).wait()
             return result
         except Exception as err:
             logging.info(
@@ -248,14 +317,15 @@
 
     def remove_security_group(self, resource_group_name, network_security_group_name):
         try:
-            result = self.network_client.network_security_groups.delete(
+            result = self.network_client.network_security_groups.begin_delete(
                 resource_group_name,
                 network_security_group_name
             )
             return result
         except Exception as err:
             logging.info(
-                "Unable to remove security group: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to remove security group: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to remove security group",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
@@ -263,7 +333,7 @@
 
     def create_datalake_store(self, resource_group_name, datalake_name, region, tags):
         try:
-            result = self.datalake_client.account.create(
+            result = self.datalake_client.accounts.create(
                 resource_group_name,
                 datalake_name,
                 {
@@ -278,7 +348,8 @@
             return result
         except Exception as err:
             logging.info(
-                "Unable to create Data Lake store: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to create Data Lake store: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to create Data Lake store",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
@@ -286,14 +357,15 @@
 
     def delete_datalake_store(self, resource_group_name, datalake_name):
         try:
-            result = self.datalake_client.account.delete(
+            result = self.datalake_client.accounts.delete(
                 resource_group_name,
                 datalake_name
             ).wait()
             return result
         except Exception as err:
             logging.info(
-                "Unable to remove Data Lake store: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to remove Data Lake store: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to remove Data Lake store",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
@@ -301,12 +373,13 @@
 
     def create_datalake_directory(self, datalake_name, dir_name):
         try:
-            datalake_client = core.AzureDLFileSystem(self.dl_filesystem_creds, store_name=datalake_name)
+            datalake_client = core.AzureDLFileSystem(store_name=datalake_name, token=self.dl_filesystem_creds)
             result = datalake_client.mkdir(dir_name)
             return result
         except Exception as err:
             logging.info(
-                "Unable to create Data Lake directory: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to create Data Lake directory: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to create Data Lake directory",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
@@ -314,7 +387,7 @@
 
     def chown_datalake_directory(self, datalake_name, dir_name, ad_user='', ad_group=''):
         try:
-            datalake_client = core.AzureDLFileSystem(self.dl_filesystem_creds, store_name=datalake_name)
+            datalake_client = core.AzureDLFileSystem(store_name=datalake_name, token=self.dl_filesystem_creds)
             if ad_user and ad_group:
                 result = datalake_client.chown(dir_name, owner=ad_user, group=ad_group)
             elif ad_user and not ad_group:
@@ -333,7 +406,7 @@
 
     def chmod_datalake_directory(self, datalake_name, dir_name, mod):
         try:
-            datalake_client = core.AzureDLFileSystem(self.dl_filesystem_creds, store_name=datalake_name)
+            datalake_client = core.AzureDLFileSystem(store_name=datalake_name, token=self.dl_filesystem_creds)
             result = datalake_client.chmod(dir_name, mod)
             return result
         except Exception as err:
@@ -348,12 +421,13 @@
     def set_user_permissions_to_datalake_directory(self, datalake_name, dir_name, ad_user, mod='rwx'):
         try:
             acl_specification = 'user:{}:{}'.format(ad_user, mod)
-            datalake_client = core.AzureDLFileSystem(self.dl_filesystem_creds, store_name=datalake_name)
+            datalake_client = core.AzureDLFileSystem(store_name=datalake_name, token=self.dl_filesystem_creds)
             result = datalake_client.modify_acl_entries(path=dir_name, acl_spec=acl_specification)
             return result
         except Exception as err:
             logging.info(
-                "Unable to set user permission to Data Lake directory: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                "Unable to set user permission to Data Lake directory: " + str(
+                    err) + "\n Traceback: " + traceback.print_exc(
                     file=sys.stdout))
             append_result(str({"error": "Unable to set user permission to Data Lake directory",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
@@ -363,12 +437,13 @@
     def unset_user_permissions_to_datalake_directory(self, datalake_name, dir_name, ad_user):
         try:
             acl_specification = 'user:{}'.format(ad_user)
-            datalake_client = core.AzureDLFileSystem(self.dl_filesystem_creds, store_name=datalake_name)
+            datalake_client = core.AzureDLFileSystem(store_name=datalake_name, token=self.dl_filesystem_creds)
             result = datalake_client.remove_acl_entries(path=dir_name, acl_spec=acl_specification)
             return result
         except Exception as err:
             logging.info(
-                "Unable to unset user permission to Data Lake directory: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                "Unable to unset user permission to Data Lake directory: " + str(
+                    err) + "\n Traceback: " + traceback.print_exc(
                     file=sys.stdout))
             append_result(str({"error": "Unable to unset user permission to Data Lake directory",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
@@ -377,37 +452,67 @@
 
     def remove_datalake_directory(self, datalake_name, dir_name):
         try:
-            datalake_client = core.AzureDLFileSystem(self.dl_filesystem_creds, store_name=datalake_name)
-            result = datalake_client.rm(dir_name, recursive=True)
+            datalake_client = core.AzureDLFileSystem(store_name=datalake_name, token=self.dl_filesystem_creds)
+            result = datalake_client.remove(dir_name, recursive=True)
             return result
         except Exception as err:
             logging.info(
-                "Unable to delete Data Lake directory: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to delete Data Lake directory: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to delete Data Lake directory",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
             traceback.print_exc(file=sys.stdout)
 
-    def create_storage_account(self, resource_group_name, account_name, region, tags):
+    def create_storage_account(self, resource_group_name, account_name, region, tags, kind='BlobStorage'):
         try:
-            result = self.storage_client.storage_accounts.create(
+            ssn_network_id = datalab.meta_lib.AzureMeta().get_subnet(resource_group_name,
+                                                                     vpc_name=os.environ['azure_vpc_name'],
+                                                                     subnet_name=os.environ['azure_subnet_name']).id
+            edge_network_id = datalab.meta_lib.AzureMeta().get_subnet(resource_group_name,
+                                                                      vpc_name=os.environ['azure_vpc_name'],
+                                                                      subnet_name='{}-{}-{}-subnet'.format(
+                                                                          os.environ['conf_service_base_name'],
+                                                                          (os.environ['project_name']),
+                                                                          (os.environ['endpoint_name']))).id
+            result = self.storage_client.storage_accounts.begin_create(
                 resource_group_name,
                 account_name,
                 {
                     "sku": {"name": "Standard_LRS"},
-                    "kind": "BlobStorage",
-                    "location":  region,
+                    "kind": kind,
+                    "location": region,
                     "tags": tags,
                     "access_tier": "Hot",
+                    "minimumTlsVersion": "TLS1_2",
                     "encryption": {
+                        "key_source": "Microsoft.Storage",
                         "services": {"blob": {"enabled": True}}
+                    },
+                    "AllowBlobPublicAccess": "false",
+                    "network_rule_set": {
+                        "bypass": "Logging, Metrics, AzureServices",
+                        "virtual_network_rules": [
+                            {
+                                "virtual_network_resource_id": ssn_network_id,
+                                "action": "Allow",
+                                "state": "Succeeded"
+                            },
+                            {
+                                "virtual_network_resource_id": edge_network_id,
+                                "action": "Allow",
+                                "state": "Succeeded"
+                            }
+                        ],
+                        "default_action": "Deny"
                     }
                 }
             ).wait()
             return result
         except Exception as err:
             logging.info(
-                "Unable to create Storage account: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to create Storage account: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to create Storage account",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
@@ -419,24 +524,32 @@
                 resource_group_name,
                 account_name
             )
+            logging.info("Storage account {} was removed.".format(account_name))
             return result
         except Exception as err:
             logging.info(
-                "Unable to remove Storage account: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to remove Storage account: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to remove Storage account",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
             traceback.print_exc(file=sys.stdout)
 
-    def create_blob_container(self, resource_group_name, account_name, container_name):
+    def create_blob_container(self, account_name, container_name):
         try:
-            secret_key = datalab.meta_lib.AzureMeta().list_storage_keys(resource_group_name, account_name)[0]
-            block_blob_service = BlockBlobService(account_name=account_name, account_key=secret_key)
-            result = block_blob_service.create_container(container_name)
+            block_blob_service = BlobServiceClient(account_url="https://" + account_name + ".blob.core.windows.net/",
+                                                   credential=self.credential)
+            result = block_blob_service.create_container(
+                container_name,
+                {
+                    "public_access": "Off"
+                }
+            )
             return result
         except Exception as err:
             logging.info(
-                "Unable to create blob container: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to create blob container: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to create blob container",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
@@ -444,14 +557,15 @@
 
     def upload_to_container(self, resource_group_name, account_name, container_name, files):
         try:
-            secret_key = datalab.meta_lib.AzureMeta().list_storage_keys(resource_group_name, account_name)[0]
-            block_blob_service = BlockBlobService(account_name=account_name, account_key=secret_key)
+            block_blob_service = BlobServiceClient(account_url="https://" + account_name + ".blob.core.windows.net/",
+                                                   credential=self.credential)
             for filename in files:
                 block_blob_service.create_blob_from_path(container_name, filename, filename)
             return ''
         except Exception as err:
             logging.info(
-                "Unable to upload files to container: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to upload files to container: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to upload files to container",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
@@ -459,8 +573,8 @@
 
     def download_from_container(self, resource_group_name, account_name, container_name, files):
         try:
-            secret_key = datalab.meta_lib.AzureMeta().list_storage_keys(resource_group_name, account_name)[0]
-            block_blob_service = BlockBlobService(account_name=account_name, account_key=secret_key)
+            block_blob_service = BlobServiceClient(account_url="https://" + account_name + ".blob.core.windows.net/",
+                                                   credential=self.credential)
             for filename in files:
                 block_blob_service.get_blob_to_path(container_name, filename, filename)
             return ''
@@ -468,7 +582,8 @@
             return ''
         except Exception as err:
             logging.info(
-                "Unable to download files from container: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to download files from container: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to download files from container",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
@@ -476,7 +591,7 @@
 
     def create_static_public_ip(self, resource_group_name, ip_name, region, instance_name, tags):
         try:
-            self.network_client.public_ip_addresses.create_or_update(
+            self.network_client.public_ip_addresses.begin_create_or_update(
                 resource_group_name,
                 ip_name,
                 {
@@ -492,22 +607,43 @@
             return datalab.meta_lib.AzureMeta().get_static_ip(resource_group_name, ip_name).ip_address
         except Exception as err:
             logging.info(
-                "Unable to create static IP address: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to create static IP address: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to create static IP address",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
             traceback.print_exc(file=sys.stdout)
 
+    def update_disk_access(self, resource_group_name, disk_name):
+        try:
+            result = self.compute_client.disks.begin_update(
+                resource_group_name,
+                disk_name,
+                {
+                    "network_access_policy": "DenyAll"
+                }
+            ).wait()
+            return result
+        except Exception as err:
+            logging.info(
+                "Unable to deny network access for disk: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
+            append_result(str({"error": "Unable to deny network access for disk",
+                               "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
+                                   file=sys.stdout)}))
+            traceback.print_exc(file=sys.stdout)
+
     def delete_static_public_ip(self, resource_group_name, ip_name):
         try:
-            result = self.network_client.public_ip_addresses.delete(
+            result = self.network_client.public_ip_addresses.begin_delete(
                 resource_group_name,
                 ip_name
             ).wait()
             return result
         except Exception as err:
             logging.info(
-                "Unable to delete static IP address: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to delete static IP address: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to delete static IP address",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
@@ -793,7 +929,7 @@
                 }
             else:
                 parameters = {}
-            result = self.compute_client.virtual_machines.create_or_update(
+            result = self.compute_client.virtual_machines.begin_create_or_update(
                 resource_group_name, instance_name, parameters
             ).wait()
             AzureActions().tag_disks(resource_group_name, instance_name)
@@ -813,11 +949,11 @@
             tags_copy = disk.tags.copy()
             tags_copy['Name'] = tags_copy['Name'] + postfix_list[inx]
             disk.tags = tags_copy
-            self.compute_client.disks.create_or_update(resource_group_name, disk.name, disk)
+            self.compute_client.disks.begin_create_or_update(resource_group_name, disk.name, disk)
 
     def stop_instance(self, resource_group_name, instance_name):
         try:
-            result = self.compute_client.virtual_machines.deallocate(resource_group_name, instance_name).wait()
+            result = self.compute_client.virtual_machines.begin_deallocate(resource_group_name, instance_name).wait()
             return result
         except Exception as err:
             logging.info(
@@ -829,7 +965,7 @@
 
     def start_instance(self, resource_group_name, instance_name):
         try:
-            result = self.compute_client.virtual_machines.start(resource_group_name, instance_name).wait()
+            result = self.compute_client.virtual_machines.begin_start(resource_group_name, instance_name).wait()
             return result
         except Exception as err:
             logging.info(
@@ -843,8 +979,8 @@
         try:
             instance_parameters = self.compute_client.virtual_machines.get(resource_group_name, instance_name)
             instance_parameters.tags = tags
-            result = self.compute_client.virtual_machines.create_or_update(resource_group_name, instance_name,
-                                                                           instance_parameters)
+            result = self.compute_client.virtual_machines.begin_create_or_update(resource_group_name, instance_name,
+                                                                                 instance_parameters)
             return result
         except Exception as err:
             logging.info(
@@ -856,7 +992,7 @@
 
     def remove_instance(self, resource_group_name, instance_name):
         try:
-            result = self.compute_client.virtual_machines.delete(resource_group_name, instance_name).wait()
+            result = self.compute_client.virtual_machines.begin_delete(resource_group_name, instance_name).wait()
             print("Instance {} has been removed".format(instance_name))
             # Removing instance disks
             disk_names = []
@@ -870,7 +1006,7 @@
             # Removing public static IP address and network interfaces
             network_interface_name = instance_name + '-nif'
             for j in datalab.meta_lib.AzureMeta().get_network_interface(resource_group_name,
-                                                                network_interface_name).ip_configurations:
+                                                                        network_interface_name).ip_configurations:
                 self.delete_network_if(resource_group_name, network_interface_name)
                 print("Network interface {} has been removed".format(network_interface_name))
                 if j.public_ip_address:
@@ -888,7 +1024,7 @@
 
     def remove_disk(self, resource_group_name, disk_name):
         try:
-            result = self.compute_client.disks.delete(resource_group_name, disk_name).wait()
+            result = self.compute_client.disks.begin_delete(resource_group_name, disk_name).wait()
             return result
         except Exception as err:
             logging.info(
@@ -904,10 +1040,13 @@
     def create_network_if(self, resource_group_name, vpc_name, subnet_name, interface_name, region, security_group_name,
                           tags, public_ip_name="None"):
         try:
-            subnet_cidr = datalab.meta_lib.AzureMeta().get_subnet(resource_group_name, vpc_name, subnet_name).address_prefix.split('/')[0]
+            subnet_cidr = \
+            datalab.meta_lib.AzureMeta().get_subnet(resource_group_name, vpc_name, subnet_name).address_prefix.split(
+                '/')[0]
             private_ip = datalab.meta_lib.AzureMeta().check_free_ip(resource_group_name, vpc_name, subnet_cidr)
             subnet_id = datalab.meta_lib.AzureMeta().get_subnet(resource_group_name, vpc_name, subnet_name).id
-            security_group_id = datalab.meta_lib.AzureMeta().get_security_group(resource_group_name, security_group_name).id
+            security_group_id = datalab.meta_lib.AzureMeta().get_security_group(resource_group_name,
+                                                                                security_group_name).id
             if public_ip_name == "None":
                 ip_params = [{
                     "name": interface_name,
@@ -932,7 +1071,7 @@
                         "id": subnet_id
                     }
                 }]
-            result = self.network_client.network_interfaces.create_or_update(
+            result = self.network_client.network_interfaces.begin_create_or_update(
                 resource_group_name,
                 interface_name,
                 {
@@ -951,7 +1090,8 @@
             return network_interface_id
         except Exception as err:
             logging.info(
-                "Unable to create network interface: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to create network interface: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to create network interface",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
@@ -959,11 +1099,12 @@
 
     def delete_network_if(self, resource_group_name, interface_name):
         try:
-            result = self.network_client.network_interfaces.delete(resource_group_name, interface_name).wait()
+            result = self.network_client.network_interfaces.begin_delete(resource_group_name, interface_name).wait()
             return result
         except Exception as err:
             logging.info(
-                "Unable to delete network interface: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+                "Unable to delete network interface: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
             append_result(str({"error": "Unable to delete network interface",
                                "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
                                    file=sys.stdout)}))
@@ -979,9 +1120,10 @@
                 if os.environ['notebook_multiple_clusters'] == 'true':
                     try:
                         livy_port = conn.sudo("cat /opt/" + cluster_name +
-                                         "/livy/conf/livy.conf | grep livy.server.port | tail -n 1 | awk '{printf $3}'").stdout.replace('\n','')
+                                              "/livy/conf/livy.conf | grep livy.server.port | tail -n 1 | awk '{printf $3}'").stdout.replace(
+                            '\n', '')
                         process_number = conn.sudo("netstat -natp 2>/dev/null | grep ':" + livy_port +
-                                              "' | awk '{print $7}' | sed 's|/.*||g'").stdout.replace('\n','')
+                                                   "' | awk '{print $7}' | sed 's|/.*||g'").stdout.replace('\n', '')
                         conn.sudo('kill -9 ' + process_number)
                         conn.sudo('systemctl disable livy-server-' + livy_port)
                     except:
@@ -1018,6 +1160,44 @@
                 conn.sudo('rm -rf /home/{}/.ensure_dir/dataengine_{}_interpreter_ensured'.format(os_user, cluster_name))
             if exists(conn, '/home/{}/.ensure_dir/rstudio_dataengine_ensured'.format(os_user)):
                 datalab.fab.remove_rstudio_dataengines_kernel(os.environ['computational_name'], os_user)
+            if exists(conn, '/home/{}/.ensure_dir/dataengine-service_{}_interpreter_ensured'.format(os_user,
+                                                                                                    cluster_name)):
+                conn.sudo("rm -rf /home/{}/.ensure_dir/dataengine-service_interpreter_ensure".format(os_user))
+                zeppelin_url = 'http://' + private + ':8080/api/interpreter/setting/'
+                opener = urllib.request.build_opener(urllib.request.ProxyHandler({}))
+                req = opener.open(urllib.request.Request(zeppelin_url))
+                r_text = req.read()
+                interpreter_json = json.loads(r_text)
+                interpreter_prefix = cluster_name
+                for interpreter in interpreter_json['body']:
+                    if interpreter_prefix in interpreter['name']:
+                        print("Interpreter with ID: {0} and name: {1} will be removed from zeppelin!".
+                              format(interpreter['id'], interpreter['name']))
+                        request = urllib.request.Request(zeppelin_url + interpreter['id'], data=''.encode())
+                        request.get_method = lambda: 'DELETE'
+                        url = opener.open(request)
+                        print(url.read())
+                conn.sudo('chown ' + os_user + ':' + os_user + ' -R /opt/zeppelin/')
+                conn.sudo('systemctl daemon-reload')
+                conn.sudo("service zeppelin-notebook stop")
+                conn.sudo("service zeppelin-notebook start")
+                zeppelin_restarted = False
+                while not zeppelin_restarted:
+                    conn.sudo('sleep 5')
+                    result = conn.sudo('nmap -p 8080 localhost | grep "closed" > /dev/null; echo $?').stdout
+                    result = result[:1]
+                    if result == '1':
+                        zeppelin_restarted = True
+                conn.sudo('sleep 5')
+                conn.sudo('rm -rf /home/{}/.ensure_dir/dataengine-service_{}_interpreter_ensured'.format(os_user,
+                                                                                                         cluster_name))
+            if exists(conn, '/home/{}/.ensure_dir/hdinsight_secret_ensured'.format(os_user)):
+                conn.sudo("sed -i '/-access-password/d' /home/{}/.Renviron".format(os_user))
+            if exists(conn, '/home/{}/.ensure_dir/sparkmagic_kernels_ensured'.format(os_user)):
+                conn.sudo('rm -rf /home/{0}/.local/share/jupyter/kernels/pysparkkernel/ '
+                          '/home/{0}/.local/share/jupyter/kernels/sparkkernel/ '
+                          '/home/{0}/.sparkmagic/ '
+                          '/home/{0}/.ensure_dir/sparkmagic_kernels_ensured'.format(os_user))
             conn.sudo('rm -rf  /opt/' + cluster_name + '/')
             print("Notebook's {} kernels were removed".format(private))
         except Exception as err:
@@ -1030,10 +1210,10 @@
     def create_image_from_instance(self, resource_group_name, instance_name, region, image_name, tags):
         try:
             instance_id = datalab.meta_lib.AzureMeta().get_instance(resource_group_name, instance_name).id
-            self.compute_client.virtual_machines.deallocate(resource_group_name, instance_name).wait()
+            self.compute_client.virtual_machines.begin_deallocate(resource_group_name, instance_name).wait()
             self.compute_client.virtual_machines.generalize(resource_group_name, instance_name)
             if not datalab.meta_lib.AzureMeta().get_image(resource_group_name, image_name):
-                self.compute_client.images.create_or_update(resource_group_name, image_name, parameters={
+                self.compute_client.images.begin_create_or_update(resource_group_name, image_name, parameters={
                     "location": region,
                     "tags": json.loads(tags),
                     "source_virtual_machine": {
@@ -1051,7 +1231,7 @@
 
     def remove_image(self, resource_group_name, image_name):
         try:
-            return self.compute_client.images.delete(resource_group_name, image_name)
+            return self.compute_client.images.begin_delete(resource_group_name, image_name)
         except Exception as err:
             logging.info(
                 "Unable to remove image: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
@@ -1060,18 +1240,207 @@
                                    file=sys.stdout)}))
             traceback.print_exc(file=sys.stdout)
 
+    def create_hdinsight_cluster(self, resource_group_name, cluster_name, cluster_parameters):
+        try:
+            logging.info('Starting to create HDInsight Spark cluster {}'.format(cluster_name))
+            result = self.hdinsight_client.clusters.begin_create(resource_group_name, cluster_name, cluster_parameters)
+            cluster = datalab.meta_lib.AzureMeta().get_hdinsight_cluster(resource_group_name, cluster_name)
+            while cluster.properties.cluster_state != 'Running':
+                time.sleep(30)
+                logging.info('The cluster is being provisioned... Please wait')
+                cluster = datalab.meta_lib.AzureMeta().get_hdinsight_cluster(resource_group_name, cluster_name)
+                if cluster.properties.cluster_state in 'Error|Unknown|TimedOut':
+                    raise Exception
+            return result
+        except Exception as err:
+            logging.info(
+                "Unable to create HDInsight Spark cluster: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
+            append_result(str({"error": "Unable to create HDInsight Spark cluster",
+                               "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
+                                   file=sys.stdout)}))
+            AzureActions().terminate_hdinsight_cluster(resource_group_name, cluster_name)
+            traceback.print_exc(file=sys.stdout)
+
+    def terminate_hdinsight_cluster(self, resource_group_name, cluster_name):
+        try:
+            logging.info('Starting to terminate HDInsight cluster {}'.format(cluster_name))
+            result = self.hdinsight_client.clusters.begin_delete(resource_group_name, cluster_name)
+            cluster_status = datalab.meta_lib.AzureMeta().get_hdinsight_cluster(resource_group_name, cluster_name)
+            while cluster_status:
+                time.sleep(30)
+                logging.info('The cluster is being terminated... Please wait')
+                cluster_status = datalab.meta_lib.AzureMeta().get_hdinsight_cluster(resource_group_name, cluster_name)
+            return result
+        except Exception as err:
+            logging.info(
+                "Unable to terminate HDInsight Spark cluster: " + str(err) + "\n Traceback: " + traceback.print_exc(
+                    file=sys.stdout))
+            append_result(str({"error": "Unable to terminate HDInsight Spark cluster",
+                               "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
+                                   file=sys.stdout)}))
+            traceback.print_exc(file=sys.stdout)
+
+
+def configure_zeppelin_hdinsight_interpreter(cluster_name, os_user, headnode_ip):
+    try:
+        # (self, emr_version, cluster_name, region, spark_dir, os_user, yarn_dir, bucket,
+        #                                            user_name, endpoint_url, multiple_emrs)
+        # port_number_found = False
+        # zeppelin_restarted = False
+        default_port = '8998'
+        # get_cluster_python_version(region, bucket, user_name, cluster_name)
+        # with open('/tmp/python_version') as f:
+        #     python_version = f.read()
+        # python_version = python_version[0:5]
+        # livy_port = ''
+        # livy_path = '/opt/{0}/{1}/livy/'.format(emr_version, cluster_name)
+        # spark_libs = "/opt/{0}/jars/usr/share/aws/aws-java-sdk/aws-java-sdk-core*.jar " \
+        #              "/opt/{0}/jars/usr/lib/hadoop/hadoop-aws*.jar " \
+        #              "/opt/{0}/jars/usr/share/aws/aws-java-sdk/aws-java-sdk-s3-*.jar " \
+        #              "/opt/{0}/jars/usr/lib/hadoop-lzo/lib/hadoop-lzo-*.jar".format(emr_version)
+        # # fix due to: Multiple py4j files found under ..../spark/python/lib
+        # # py4j-0.10.7-src.zip still in folder. Versions may varies.
+        # subprocess.run('rm /opt/{0}/{1}/spark/python/lib/py4j-src.zip'.format(emr_version, cluster_name),
+        #                shell=True, check=True)
+        #
+        # subprocess.run('echo \"Configuring emr path for Zeppelin\"', shell=True, check=True)
+        # subprocess.run('sed -i \"s/^export SPARK_HOME.*/export SPARK_HOME=\/opt\/{0}\/{1}\/spark/\" '
+        #                '/opt/zeppelin/conf/zeppelin-env.sh'.format(emr_version, cluster_name), shell=True,
+        #                check=True)
+        # subprocess.run('sed -i "s/^export HADOOP_CONF_DIR.*/export HADOOP_CONF_DIR=' + \
+        #                '\/opt\/{0}\/{1}\/conf/" /opt/{0}/{1}/spark/conf/spark-env.sh'.format(emr_version,
+        #                                                                                      cluster_name),
+        #                shell=True, check=True)
+        # subprocess.run(
+        #     'echo \"spark.jars $(ls {0} | tr \'\\n\' \',\')\" >> /opt/{1}/{2}/spark/conf/spark-defaults.conf'
+        #     .format(spark_libs, emr_version, cluster_name), shell=True, check=True)
+        # subprocess.run('sed -i "/spark.executorEnv.PYTHONPATH/d" /opt/{0}/{1}/spark/conf/spark-defaults.conf'
+        #                .format(emr_version, cluster_name), shell=True, check=True)
+        # subprocess.run('sed -i "/spark.yarn.dist.files/d" /opt/{0}/{1}/spark/conf/spark-defaults.conf'
+        #                .format(emr_version, cluster_name), shell=True, check=True)
+        # subprocess.run('sudo chown {0}:{0} -R /opt/zeppelin/'.format(os_user), shell=True, check=True)
+        # subprocess.run('sudo systemctl daemon-reload', shell=True, check=True)
+        # subprocess.run('sudo service zeppelin-notebook stop', shell=True, check=True)
+        # subprocess.run('sudo service zeppelin-notebook start', shell=True, check=True)
+        # while not zeppelin_restarted:
+        #     subprocess.run('sleep 5', shell=True, check=True)
+        #     result = subprocess.run('sudo bash -c "nmap -p 8080 localhost | grep closed > /dev/null" ; echo $?',
+        #                             capture_output=True, shell=True, check=True).stdout.decode('UTF-8').rstrip(
+        #         "\n\r")
+        #     result = result[:1]
+        #     if result == '1':
+        #         zeppelin_restarted = True
+        # subprocess.run('sleep 5', shell=True, check=True)
+        subprocess.run('echo \"Configuring HDinsight livy interpreter for Zeppelin\"', shell=True, check=True)
+        if False:  # multiple_emrs == 'true':
+            pass
+            # while not port_number_found:
+            #     port_free = subprocess.run('sudo bash -c "nmap -p ' + str(default_port) +
+            #                                ' localhost | grep closed > /dev/null" ; echo $?', capture_output=True,
+            #                                shell=True, check=True).stdout.decode('UTF-8').rstrip("\n\r")
+            #     port_free = port_free[:1]
+            #     if port_free == '0':
+            #         livy_port = default_port
+            #         port_number_found = True
+            #     else:
+            #         default_port += 1
+            # subprocess.run(
+            #     'sudo echo "livy.server.port = {0}" >> {1}conf/livy.conf'.format(str(livy_port), livy_path),
+            #     shell=True, check=True)
+            # subprocess.run('sudo echo "livy.spark.master = yarn" >> {}conf/livy.conf'.format(livy_path), shell=True,
+            #                check=True)
+            # if os.path.exists('{}conf/spark-blacklist.conf'.format(livy_path)):
+            #     subprocess.run('sudo sed -i "s/^/#/g" {}conf/spark-blacklist.conf'.format(livy_path), shell=True,
+            #                    check=True)
+            # subprocess.run(
+            #     ''' sudo echo "export SPARK_HOME={0}" >> {1}conf/livy-env.sh'''.format(spark_dir, livy_path),
+            #     shell=True, check=True)
+            # subprocess.run(
+            #     ''' sudo echo "export HADOOP_CONF_DIR={0}" >> {1}conf/livy-env.sh'''.format(yarn_dir, livy_path),
+            #     shell=True, check=True)
+            # subprocess.run(''' sudo echo "export PYSPARK3_PYTHON=python{0}" >> {1}conf/livy-env.sh'''.format(
+            #     python_version[0:3],
+            #     livy_path), shell=True, check=True)
+            # template_file = "/tmp/dataengine-service_interpreter.json"
+            # fr = open(template_file, 'r+')
+            # text = fr.read()
+            # text = text.replace('CLUSTER_NAME', cluster_name)
+            # text = text.replace('SPARK_HOME', spark_dir)
+            # text = text.replace('ENDPOINTURL', endpoint_url)
+            # text = text.replace('LIVY_PORT', str(livy_port))
+            # fw = open(template_file, 'w')
+            # fw.write(text)
+            # fw.close()
+            # for _ in range(5):
+            #     try:
+            #         subprocess.run("curl --noproxy localhost -H 'Content-Type: application/json' -X POST -d " +
+            #                        "@/tmp/dataengine-service_interpreter.json http://localhost:8080/api/interpreter/setting",
+            #                        shell=True, check=True)
+            #         break
+            #     except:
+            #         subprocess.run('sleep 5', shell=True, check=True)
+            # subprocess.run('sudo cp /opt/livy-server-cluster.service /etc/systemd/system/livy-server-{}.service'
+            #                .format(str(livy_port)), shell=True, check=True)
+            # subprocess.run("sudo sed -i 's|OS_USER|{0}|' /etc/systemd/system/livy-server-{1}.service"
+            #                .format(os_user, str(livy_port)), shell=True, check=True)
+            # subprocess.run("sudo sed -i 's|LIVY_PATH|{0}|' /etc/systemd/system/livy-server-{1}.service"
+            #                .format(livy_path, str(livy_port)), shell=True, check=True)
+            # subprocess.run('sudo chmod 644 /etc/systemd/system/livy-server-{}.service'.format(str(livy_port)),
+            #                shell=True, check=True)
+            # subprocess.run("sudo systemctl daemon-reload", shell=True, check=True)
+            # subprocess.run("sudo systemctl enable livy-server-{}".format(str(livy_port)), shell=True, check=True)
+            # subprocess.run('sudo systemctl start livy-server-{}'.format(str(livy_port)), shell=True, check=True)
+        else:
+            template_file = "/tmp/dataengine-service_interpreter.json"
+            fr = open(template_file, 'r+')
+            text = fr.read()
+            text = text.replace('CLUSTERNAME', cluster_name)
+            text = text.replace('HEADNODEIP', headnode_ip)
+            text = text.replace('PORT', default_port)
+            # text = text.replace('PYTHONVERSION', p_version)
+            # text = text.replace('SPARK_HOME', spark_dir)
+            # text = text.replace('PYTHONVER_SHORT', p_version[:1])
+            # text = text.replace('ENDPOINTURL', endpoint_url)
+            # text = text.replace('DATAENGINE-SERVICE_VERSION', emr_version)
+            tmp_file = "/tmp/hdinsight_interpreter_livy.json"
+            fw = open(tmp_file, 'w')
+            fw.write(text)
+            fw.close()
+            for _ in range(5):
+                try:
+                    subprocess.run("curl --noproxy localhost -H 'Content-Type: application/json' -X POST "
+                                   "-d @/tmp/hdinsight_interpreter_livy.json "
+                                   "http://localhost:8080/api/interpreter/setting",
+                                   shell=True, check=True)
+                    break
+                except:
+                    subprocess.run('sleep 5', shell=True, check=True)
+        subprocess.run(
+            'touch /home/' + os_user + '/.ensure_dir/dataengine-service_' + cluster_name + '_interpreter_ensured',
+            shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc(file=sys.stdout)
+        sys.exit(1)
+
 
 def ensure_local_jars(os_user, jars_dir):
-    if not exists(datalab.fab.conn,'/home/{}/.ensure_dir/local_jars_ensured'.format(os_user)):
+    if not exists(datalab.fab.conn, '/home/{}/.ensure_dir/local_jars_ensured'.format(os_user)):
         try:
-            hadoop_version = datalab.fab.conn.sudo("ls /opt/spark/jars/hadoop-common* | sed -n 's/.*\([0-9]\.[0-9]\.[0-9]\).*/\\1/p'").stdout.replace('\n','')
+            hadoop_version = datalab.fab.conn.sudo(
+                "ls /opt/spark/jars/hadoop-common* | sed -n 's/.*\([0-9]\.[0-9]\.[0-9]\).*/\\1/p'").stdout.replace('\n',
+                                                                                                                   '')
             print("Downloading local jars for Azure")
             datalab.fab.conn.sudo('mkdir -p {}'.format(jars_dir))
             if os.environ['azure_datalake_enable'] == 'false':
                 datalab.fab.conn.sudo('wget https://repo1.maven.org/maven2/org/apache/hadoop/hadoop-azure/{0}/hadoop-azure-{0}.jar -O \
                                  {1}hadoop-azure-{0}.jar'.format(hadoop_version, jars_dir))
                 datalab.fab.conn.sudo('wget https://repo1.maven.org/maven2/com/microsoft/azure/azure-storage/{0}/azure-storage-{0}.jar \
-                    -O {1}azure-storage-{0}.jar'.format('2.2.0', jars_dir))
+                    -O {1}azure-storage-{0}.jar'.format('8.6.6', jars_dir))
+                datalab.fab.conn.sudo('wget https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-util/{0}/jetty-util-{0}.jar \
+                    -O {1}jetty-util-{0}.jar'.format('9.4.46.v20220331', jars_dir))
+                datalab.fab.conn.sudo('wget https://repo1.maven.org/maven2/org/eclipse/jetty/jetty-util-ajax/{0}/jetty-util-ajax-{0}.jar \
+                    -O {1}jetty-util-ajax-{0}.jar'.format('9.4.46.v20220331', jars_dir))
             else:
                 datalab.fab.conn.sudo('wget https://repo1.maven.org/maven2/org/apache/hadoop/hadoop-azure/{0}/hadoop-azure-{0}.jar -O \
                                  {1}hadoop-azure-{0}.jar'.format('3.0.0', jars_dir))
@@ -1100,7 +1469,8 @@
         spark_jars_paths = None
         if exists(datalab.fab.conn, '/opt/spark/conf/spark-defaults.conf'):
             try:
-                spark_jars_paths = datalab.fab.conn.sudo('cat /opt/spark/conf/spark-defaults.conf | grep -e "^spark.jars " ').stdout
+                spark_jars_paths = datalab.fab.conn.sudo(
+                    'cat /opt/spark/conf/spark-defaults.conf | grep -e "^spark.jars " ').stdout
             except:
                 spark_jars_paths = None
         user_storage_account_tag = "{}-{}-{}-bucket".format(os.environ['conf_service_base_name'],
@@ -1108,7 +1478,8 @@
                                                             os.environ['endpoint_name'].lower())
         shared_storage_account_tag = '{0}-{1}-shared-bucket'.format(os.environ['conf_service_base_name'],
                                                                     os.environ['endpoint_name'].lower())
-        for storage_account in datalab.meta_lib.AzureMeta().list_storage_accounts(os.environ['azure_resource_group_name']):
+        for storage_account in datalab.meta_lib.AzureMeta().list_storage_accounts(
+                os.environ['azure_resource_group_name']):
             if user_storage_account_tag == storage_account.tags["Name"]:
                 user_storage_account_name = storage_account.name
                 user_storage_account_key = datalab.meta_lib.AzureMeta().list_storage_keys(
@@ -1121,10 +1492,13 @@
             datalab.fab.conn.put(templates_dir + 'core-site-storage.xml', '/tmp/core-site.xml')
         else:
             datalab.fab.conn.put(templates_dir + 'core-site-datalake.xml', '/tmp/core-site.xml')
-        datalab.fab.conn.sudo('sed -i "s|USER_STORAGE_ACCOUNT|{}|g" /tmp/core-site.xml'.format(user_storage_account_name))
-        datalab.fab.conn.sudo('sed -i "s|SHARED_STORAGE_ACCOUNT|{}|g" /tmp/core-site.xml'.format(shared_storage_account_name))
+        datalab.fab.conn.sudo(
+            'sed -i "s|USER_STORAGE_ACCOUNT|{}|g" /tmp/core-site.xml'.format(user_storage_account_name))
+        datalab.fab.conn.sudo(
+            'sed -i "s|SHARED_STORAGE_ACCOUNT|{}|g" /tmp/core-site.xml'.format(shared_storage_account_name))
         datalab.fab.conn.sudo('sed -i "s|USER_ACCOUNT_KEY|{}|g" /tmp/core-site.xml'.format(user_storage_account_key))
-        datalab.fab.conn.sudo('sed -i "s|SHARED_ACCOUNT_KEY|{}|g" /tmp/core-site.xml'.format(shared_storage_account_key))
+        datalab.fab.conn.sudo(
+            'sed -i "s|SHARED_ACCOUNT_KEY|{}|g" /tmp/core-site.xml'.format(shared_storage_account_key))
         if os.environ['azure_datalake_enable'] == 'true':
             client_id = os.environ['azure_application_id']
             refresh_token = os.environ['azure_user_refresh_token']
@@ -1136,18 +1510,22 @@
         else:
             datalab.fab.conn.sudo('rm -f /opt/hadoop/etc/hadoop/core-site.xml')
             datalab.fab.conn.sudo('mv /tmp/core-site.xml /opt/hadoop/etc/hadoop/core-site.xml')
-        datalab.fab.conn.put(templates_dir + 'notebook_spark-defaults_local.conf', '/tmp/notebook_spark-defaults_local.conf')
+        datalab.fab.conn.put(templates_dir + 'notebook_spark-defaults_local.conf',
+                             '/tmp/notebook_spark-defaults_local.conf')
         datalab.fab.conn.sudo("jar_list=`find {} -name '*.jar' | tr '\\n' ','` ; echo \"spark.jars   $jar_list\" >> \
               /tmp/notebook_spark-defaults_local.conf".format(jars_dir))
         datalab.fab.conn.sudo('cp -f /tmp/notebook_spark-defaults_local.conf /opt/spark/conf/spark-defaults.conf')
         if memory_type == 'driver':
             spark_memory = datalab.fab.get_spark_memory()
             datalab.fab.conn.sudo('sed -i "/spark.*.memory/d" /opt/spark/conf/spark-defaults.conf')
-            datalab.fab.conn.sudo('''bash -c 'echo "spark.{0}.memory {1}m" >> /opt/spark/conf/spark-defaults.conf' '''.format(memory_type,
-                                                                                              spark_memory))
-        if not exists(datalab.fab.conn,'/opt/spark/conf/spark-env.sh'):
+            datalab.fab.conn.sudo(
+                '''bash -c 'echo "spark.{0}.memory {1}m" >> /opt/spark/conf/spark-defaults.conf' '''.format(memory_type,
+                                                                                                            spark_memory))
+        if not exists(datalab.fab.conn, '/opt/spark/conf/spark-env.sh'):
             datalab.fab.conn.sudo('mv /opt/spark/conf/spark-env.sh.template /opt/spark/conf/spark-env.sh')
-        java_home = datalab.fab.conn.run("update-alternatives --query java | grep -o --color=never \'/.*/java-8.*/jre\'").stdout.splitlines()[0].replace('\n','')
+        java_home = datalab.fab.conn.run(
+            "update-alternatives --query java | grep -o --color=never \'/.*/java-8.*/jre\'").stdout.splitlines()[
+            0].replace('\n', '')
         datalab.fab.conn.sudo("echo 'export JAVA_HOME=\'{}\'' >> /opt/spark/conf/spark-env.sh".format(java_home))
         if 'spark_configurations' in os.environ:
             datalab_header = datalab.fab.conn.sudo('cat /tmp/notebook_spark-defaults_local.conf | grep "^#"').stdout
@@ -1166,13 +1544,15 @@
                                     new_spark_defaults.append(property + ' ' + config['Properties'][property])
                     new_spark_defaults.append(param)
             new_spark_defaults = set(new_spark_defaults)
-            datalab.fab.conn.sudo('''bash -c 'echo "{}" > /opt/spark/conf/spark-defaults.conf' '''.format(datalab_header))
+            datalab.fab.conn.sudo(
+                '''bash -c 'echo "{}" > /opt/spark/conf/spark-defaults.conf' '''.format(datalab_header))
             for prop in new_spark_defaults:
                 prop = prop.rstrip()
                 datalab.fab.conn.sudo('''bash -c 'echo "{}" >> /opt/spark/conf/spark-defaults.conf' '''.format(prop))
             datalab.fab.conn.sudo('sed -i "/^\s*$/d" /opt/spark/conf/spark-defaults.conf')
             if spark_jars_paths:
-                datalab.fab.conn.sudo('''bash -c 'echo "{}" >> /opt/spark/conf/spark-defaults.conf' '''.format(spark_jars_paths))
+                datalab.fab.conn.sudo(
+                    '''bash -c 'echo "{}" >> /opt/spark/conf/spark-defaults.conf' '''.format(spark_jars_paths))
     except Exception as err:
         print('Error:', str(err))
         sys.exit(1)
@@ -1183,24 +1563,34 @@
           /tmp/{1}/notebook_spark-defaults_local.conf".format(jars_dir, cluster_name), shell=True, check=True)
     if os.path.exists('{0}spark/conf/spark-defaults.conf'.format(cluster_dir)):
         additional_spark_properties = subprocess.run('diff --changed-group-format="%>" --unchanged-group-format="" '
-                                            '/tmp/{0}/notebook_spark-defaults_local.conf '
-                                            '{1}spark/conf/spark-defaults.conf | grep -v "^#"'.format(
-                                             cluster_name, cluster_dir), capture_output=True, shell=True, check=True).stdout.decode('UTF-8').rstrip("\n\r")
+                                                     '/tmp/{0}/notebook_spark-defaults_local.conf '
+                                                     '{1}spark/conf/spark-defaults.conf | grep -v "^#"'.format(
+            cluster_name, cluster_dir), capture_output=True, shell=True, check=True).stdout.decode('UTF-8').rstrip(
+            "\n\r")
         for property in additional_spark_properties.split('\n'):
-            subprocess.run('echo "{0}" >> /tmp/{1}/notebook_spark-defaults_local.conf'.format(property, cluster_name), shell=True, check=True)
+            subprocess.run('echo "{0}" >> /tmp/{1}/notebook_spark-defaults_local.conf'.format(property, cluster_name),
+                           shell=True, check=True)
     if os.path.exists('{0}'.format(cluster_dir)):
-        subprocess.run('cp -f /tmp/{0}/notebook_spark-defaults_local.conf  {1}spark/conf/spark-defaults.conf'.format(cluster_name,
-                                                                                                        cluster_dir), shell=True, check=True)
+        subprocess.run(
+            'cp -f /tmp/{0}/notebook_spark-defaults_local.conf  {1}spark/conf/spark-defaults.conf'.format(cluster_name,
+                                                                                                          cluster_dir),
+            shell=True, check=True)
         if datalake_enabled == 'false':
-            subprocess.run('cp -f /opt/spark/conf/core-site.xml {}spark/conf/'.format(cluster_dir), shell=True, check=True)
+            subprocess.run('cp -f /opt/spark/conf/core-site.xml {}spark/conf/'.format(cluster_dir), shell=True,
+                           check=True)
         else:
-            subprocess.run('cp -f /opt/hadoop/etc/hadoop/core-site.xml {}hadoop/etc/hadoop/core-site.xml'.format(cluster_dir), shell=True, check=True)
+            subprocess.run(
+                'cp -f /opt/hadoop/etc/hadoop/core-site.xml {}hadoop/etc/hadoop/core-site.xml'.format(cluster_dir),
+                shell=True, check=True)
     if spark_configs and os.path.exists('{0}'.format(cluster_dir)):
-        datalab_header = subprocess.run('cat /tmp/{0}/notebook_spark-defaults_local.conf | grep "^#"'.format(cluster_name),
-                               capture_output=True, shell=True, check=True).stdout.decode('UTF-8').rstrip("\n\r")
+        datalab_header = subprocess.run(
+            'cat /tmp/{0}/notebook_spark-defaults_local.conf | grep "^#"'.format(cluster_name),
+            capture_output=True, shell=True, check=True).stdout.decode('UTF-8').rstrip("\n\r")
         spark_configurations = ast.literal_eval(spark_configs)
         new_spark_defaults = list()
-        spark_defaults = subprocess.run('cat {0}spark/conf/spark-defaults.conf'.format(cluster_dir), capture_output=True, shell=True, check=True).stdout.decode('UTF-8').rstrip("\n\r")
+        spark_defaults = subprocess.run('cat {0}spark/conf/spark-defaults.conf'.format(cluster_dir),
+                                        capture_output=True, shell=True, check=True).stdout.decode('UTF-8').rstrip(
+            "\n\r")
         current_spark_properties = spark_defaults.split('\n')
         for param in current_spark_properties:
             if param.split(' ')[0] != '#':
@@ -1213,11 +1603,14 @@
                                 new_spark_defaults.append(property + ' ' + config['Properties'][property])
                 new_spark_defaults.append(param)
         new_spark_defaults = set(new_spark_defaults)
-        subprocess.run("echo '{0}' > {1}/spark/conf/spark-defaults.conf".format(datalab_header, cluster_dir), shell=True, check=True)
+        subprocess.run("echo '{0}' > {1}/spark/conf/spark-defaults.conf".format(datalab_header, cluster_dir),
+                       shell=True, check=True)
         for prop in new_spark_defaults:
             prop = prop.rstrip()
-            subprocess.run('echo "{0}" >> {1}/spark/conf/spark-defaults.conf'.format(prop, cluster_dir), shell=True, check=True)
-        subprocess.run('sed -i "/^\s*$/d" {0}/spark/conf/spark-defaults.conf'.format(cluster_dir), shell=True, check=True)
+            subprocess.run('echo "{0}" >> {1}/spark/conf/spark-defaults.conf'.format(prop, cluster_dir), shell=True,
+                           check=True)
+        subprocess.run('sed -i "/^\s*$/d" {0}/spark/conf/spark-defaults.conf'.format(cluster_dir), shell=True,
+                       check=True)
 
 
 def remount_azure_disk(creds=False, os_user='', hostname='', keyfile=''):
@@ -1232,6 +1625,7 @@
     if creds:
         conn.close()
 
+
 def ensure_right_mount_paths(creds=False, os_user='', hostname='', keyfile=''):
     if creds:
         global conn
@@ -1239,16 +1633,19 @@
     else:
         conn = datalab.fab.conn
     opt_disk = conn.sudo("cat /etc/fstab | grep /opt/ | awk '{print $1}'").stdout.split('\n')[0].split('/')[2]
-    if opt_disk not in conn.sudo("lsblk | grep /opt", warn=True).stdout or opt_disk in conn.sudo("fdisk -l | grep 'BIOS boot'").stdout:
-         disk_names = conn.sudo("lsblk | grep disk | awk '{print $1}' | sort").stdout.split('\n')
-         for disk in disk_names:
-             if disk != '' and disk not in conn.sudo('lsblk | grep -E "(mnt|media)"').stdout and disk not in conn.sudo("fdisk -l | grep 'BIOS boot'").stdout:
-                 conn.sudo("umount -l /opt")
-                 conn.sudo("mount /dev/{}1 /opt".format(disk))
-                 conn.sudo('sed -i "/opt/ s|/dev/{}|/dev/{}1|g" /etc/fstab'.format(opt_disk, disk))
+    if opt_disk not in conn.sudo("lsblk | grep /opt", warn=True).stdout or opt_disk in conn.sudo(
+            "fdisk -l | grep 'BIOS boot'").stdout:
+        disk_names = conn.sudo("lsblk | grep disk | awk '{print $1}' | sort").stdout.split('\n')
+        for disk in disk_names:
+            if disk != '' and disk not in conn.sudo('lsblk | grep -E "(mnt|media)"').stdout and disk not in conn.sudo(
+                    "fdisk -l | grep 'BIOS boot'").stdout:
+                conn.sudo("umount -l /opt")
+                conn.sudo("mount /dev/{}1 /opt".format(disk))
+                conn.sudo('sed -i "/opt/ s|/dev/{}|/dev/{}1|g" /etc/fstab'.format(opt_disk, disk))
     if creds:
         conn.close()
 
+
 def prepare_vm_for_image(creds=False, os_user='', hostname='', keyfile=''):
     if creds:
         global conn
@@ -1259,7 +1656,7 @@
 
 
 def prepare_disk(os_user):
-    if not exists(datalab.fab.conn,'/home/' + os_user + '/.ensure_dir/disk_ensured'):
+    if not exists(datalab.fab.conn, '/home/' + os_user + '/.ensure_dir/disk_ensured'):
         try:
             allow = False
             counter = 0
@@ -1294,7 +1691,8 @@
                         else:
                             sys.exit(1)
                     datalab.fab.conn.sudo('mount /dev/{}1 /opt/'.format(disk))
-                    datalab.fab.conn.sudo(''' bash -c "echo '/dev/{}1 /opt/ ext4 errors=remount-ro 0 1' >> /etc/fstab" '''.format(disk))
+                    datalab.fab.conn.sudo(
+                        ''' bash -c "echo '/dev/{}1 /opt/ ext4 errors=remount-ro 0 1' >> /etc/fstab" '''.format(disk))
 
             datalab.fab.conn.sudo('touch /home/' + os_user + '/.ensure_dir/disk_ensured')
         except Exception as err:
@@ -1305,33 +1703,51 @@
         ensure_right_mount_paths()
 
 
+def ensure_hdinsight_secret(os_user, computational_name, cluster_password):
+    if not exists(datalab.fab.conn, '/home/{}/.ensure_dir/hdinsight_secret_ensured'.format(os_user)):
+        try:
+            datalab.fab.conn.sudo('''echo '{}-access-password="{}"' >> /home/{}/.Renviron'''
+                                  .format(computational_name, cluster_password, os_user))
+            datalab.fab.conn.sudo('touch /home/{}/.ensure_dir/hdinsight_secret_ensured'.format(os_user))
+        except Exception as err:
+            print('Error:', str(err))
+            sys.exit(1)
+
+
 def ensure_local_spark(os_user, spark_link, spark_version, hadoop_version, local_spark_path):
-    if not exists(datalab.fab.conn,'/home/' + os_user + '/.ensure_dir/local_spark_ensured'):
+    if not exists(datalab.fab.conn, '/home/' + os_user + '/.ensure_dir/local_spark_ensured'):
         try:
             if os.environ['azure_datalake_enable'] == 'false':
-                datalab.fab.conn.sudo('wget ' + spark_link + ' -O /tmp/spark-' + spark_version + '-bin-hadoop' + hadoop_version + '.tgz')
-                datalab.fab.conn.sudo('tar -zxvf /tmp/spark-' + spark_version + '-bin-hadoop' + hadoop_version + '.tgz -C /opt/')
-                datalab.fab.conn.sudo('mv /opt/spark-' + spark_version + '-bin-hadoop' + hadoop_version + ' ' + local_spark_path)
+                datalab.fab.conn.sudo(
+                    'wget ' + spark_link + ' -O /tmp/spark-' + spark_version + '-bin-hadoop' + hadoop_version + '.tgz')
+                datalab.fab.conn.sudo(
+                    'tar -zxvf /tmp/spark-' + spark_version + '-bin-hadoop' + hadoop_version + '.tgz -C /opt/')
+                datalab.fab.conn.sudo(
+                    'mv /opt/spark-' + spark_version + '-bin-hadoop' + hadoop_version + ' ' + local_spark_path)
                 datalab.fab.conn.sudo('chown -R ' + os_user + ':' + os_user + ' ' + local_spark_path)
                 datalab.fab.conn.sudo('touch /home/' + os_user + '/.ensure_dir/local_spark_ensured')
             else:
                 # Downloading Spark without Hadoop
-                datalab.fab.conn.sudo('wget https://archive.apache.org/dist/spark/spark-{0}/spark-{0}-bin-without-hadoop.tgz -O /tmp/spark-{0}-bin-without-hadoop.tgz'
+                datalab.fab.conn.sudo(
+                    'wget https://archive.apache.org/dist/spark/spark-{0}/spark-{0}-bin-without-hadoop.tgz -O /tmp/spark-{0}-bin-without-hadoop.tgz'
                     .format(spark_version))
                 datalab.fab.conn.sudo('tar -zxvf /tmp/spark-{}-bin-without-hadoop.tgz -C /opt/'.format(spark_version))
                 datalab.fab.conn.sudo('mv /opt/spark-{}-bin-without-hadoop {}'.format(spark_version, local_spark_path))
                 datalab.fab.conn.sudo('chown -R {0}:{0} {1}'.format(os_user, local_spark_path))
                 # Downloading Hadoop
                 hadoop_version = '3.0.0'
-                datalab.fab.conn.sudo('wget https://archive.apache.org/dist/hadoop/common/hadoop-{0}/hadoop-{0}.tar.gz -O /tmp/hadoop-{0}.tar.gz'
+                datalab.fab.conn.sudo(
+                    'wget https://archive.apache.org/dist/hadoop/common/hadoop-{0}/hadoop-{0}.tar.gz -O /tmp/hadoop-{0}.tar.gz'
                     .format(hadoop_version))
                 datalab.fab.conn.sudo('tar -zxvf /tmp/hadoop-{0}.tar.gz -C /opt/'.format(hadoop_version))
                 datalab.fab.conn.sudo('mv /opt/hadoop-{0} /opt/hadoop/'.format(hadoop_version))
                 datalab.fab.conn.sudo('chown -R {0}:{0} /opt/hadoop/'.format(os_user))
                 # Configuring Hadoop and Spark
                 java_path = datalab.common_lib.find_java_path_remote()
-                datalab.fab.conn.sudo('echo "export JAVA_HOME={}" >> /opt/hadoop/etc/hadoop/hadoop-env.sh'.format(java_path))
-                datalab.fab.conn.sudo("""echo 'export HADOOP_CLASSPATH="$HADOOP_HOME/share/hadoop/tools/lib/*"' >> /opt/hadoop/etc/hadoop/hadoop-env.sh""")
+                datalab.fab.conn.sudo(
+                    'echo "export JAVA_HOME={}" >> /opt/hadoop/etc/hadoop/hadoop-env.sh'.format(java_path))
+                datalab.fab.conn.sudo(
+                    """echo 'export HADOOP_CLASSPATH="$HADOOP_HOME/share/hadoop/tools/lib/*"' >> /opt/hadoop/etc/hadoop/hadoop-env.sh""")
                 datalab.fab.conn.sudo('echo "export HADOOP_HOME=/opt/hadoop/" >> /opt/spark/conf/spark-env.sh')
                 datalab.fab.conn.sudo('echo "export SPARK_HOME=/opt/spark/" >> /opt/spark/conf/spark-env.sh')
                 spark_dist_classpath = datalab.fab.conn.sudo('/opt/hadoop/bin/hadoop classpath').stdout
@@ -1343,34 +1759,55 @@
             sys.exit(1)
 
 
-def install_dataengine_spark(cluster_name, spark_link, spark_version, hadoop_version, cluster_dir, os_user, datalake_enabled):
+def install_dataengine_spark(cluster_name, spark_link, spark_version, hadoop_version, cluster_dir, os_user,
+                             datalake_enabled):
     try:
         if datalake_enabled == 'false':
-            subprocess.run('wget ' + spark_link + ' -O /tmp/' + cluster_name + '/spark-' + spark_version + '-bin-hadoop' + hadoop_version + '.tgz', shell=True, check=True)
-            subprocess.run('tar -zxvf /tmp/' + cluster_name + '/spark-' + spark_version + '-bin-hadoop' + hadoop_version + '.tgz -C /opt/', shell=True, check=True)
-            subprocess.run('mv /opt/spark-' + spark_version + '-bin-hadoop' + hadoop_version + ' ' + cluster_dir + 'spark/', shell=True, check=True)
+            subprocess.run(
+                'wget ' + spark_link + ' -O /tmp/' + cluster_name + '/spark-' + spark_version + '-bin-hadoop' + hadoop_version + '.tgz',
+                shell=True, check=True)
+            subprocess.run(
+                'tar -zxvf /tmp/' + cluster_name + '/spark-' + spark_version + '-bin-hadoop' + hadoop_version + '.tgz -C /opt/',
+                shell=True, check=True)
+            subprocess.run(
+                'mv /opt/spark-' + spark_version + '-bin-hadoop' + hadoop_version + ' ' + cluster_dir + 'spark/',
+                shell=True, check=True)
             subprocess.run('chown -R ' + os_user + ':' + os_user + ' ' + cluster_dir + 'spark/', shell=True, check=True)
         else:
             # Downloading Spark without Hadoop
-            subprocess.run('wget https://archive.apache.org/dist/spark/spark-{0}/spark-{0}-bin-without-hadoop.tgz -O /tmp/{1}/spark-{0}-bin-without-hadoop.tgz'
-                 .format(spark_version, cluster_name), shell=True, check=True)
-            subprocess.run('tar -zxvf /tmp/' + cluster_name + '/spark-{}-bin-without-hadoop.tgz -C /opt/'.format(spark_version), shell=True, check=True)
-            subprocess.run('mv /opt/spark-{}-bin-without-hadoop {}spark/'.format(spark_version, cluster_dir), shell=True, check=True)
+            subprocess.run(
+                'wget https://archive.apache.org/dist/spark/spark-{0}/spark-{0}-bin-without-hadoop.tgz -O /tmp/{1}/spark-{0}-bin-without-hadoop.tgz'
+                .format(spark_version, cluster_name), shell=True, check=True)
+            subprocess.run(
+                'tar -zxvf /tmp/' + cluster_name + '/spark-{}-bin-without-hadoop.tgz -C /opt/'.format(spark_version),
+                shell=True, check=True)
+            subprocess.run('mv /opt/spark-{}-bin-without-hadoop {}spark/'.format(spark_version, cluster_dir),
+                           shell=True, check=True)
             subprocess.run('chown -R {0}:{0} {1}/spark/'.format(os_user, cluster_dir), shell=True, check=True)
             # Downloading Hadoop
             hadoop_version = '3.0.0'
-            subprocess.run('wget https://archive.apache.org/dist/hadoop/common/hadoop-{0}/hadoop-{0}.tar.gz -O /tmp/{1}/hadoop-{0}.tar.gz'
-                 .format(hadoop_version, cluster_name), shell=True, check=True)
-            subprocess.run('tar -zxvf /tmp/' + cluster_name + '/hadoop-{0}.tar.gz -C /opt/'.format(hadoop_version), shell=True, check=True)
+            subprocess.run(
+                'wget https://archive.apache.org/dist/hadoop/common/hadoop-{0}/hadoop-{0}.tar.gz -O /tmp/{1}/hadoop-{0}.tar.gz'
+                .format(hadoop_version, cluster_name), shell=True, check=True)
+            subprocess.run('tar -zxvf /tmp/' + cluster_name + '/hadoop-{0}.tar.gz -C /opt/'.format(hadoop_version),
+                           shell=True, check=True)
             subprocess.run('mv /opt/hadoop-{0} {1}hadoop/'.format(hadoop_version, cluster_dir), shell=True, check=True)
             subprocess.run('chown -R {0}:{0} {1}hadoop/'.format(os_user, cluster_dir), shell=True, check=True)
             # Configuring Hadoop and Spark
             java_path = datalab.common_lib.find_java_path_local()
-            subprocess.run('echo "export JAVA_HOME={}" >> {}hadoop/etc/hadoop/hadoop-env.sh'.format(java_path, cluster_dir), shell=True, check=True)
-            subprocess.run("""echo 'export HADOOP_CLASSPATH="$HADOOP_HOME/share/hadoop/tools/lib/*"' >> {}hadoop/etc/hadoop/hadoop-env.sh""".format(cluster_dir), shell=True, check=True)
-            subprocess.run('echo "export HADOOP_HOME={0}hadoop/" >> {0}spark/conf/spark-env.sh'.format(cluster_dir), shell=True, check=True)
-            subprocess.run('echo "export SPARK_HOME={0}spark/" >> {0}spark/conf/spark-env.sh'.format(cluster_dir), shell=True, check=True)
-            spark_dist_classpath = subprocess.run('{}hadoop/bin/hadoop classpath'.format(cluster_dir), capture_output=True, shell=True, check=True).stdout.decode('UTF-8').rstrip("\n\r")
+            subprocess.run(
+                'echo "export JAVA_HOME={}" >> {}hadoop/etc/hadoop/hadoop-env.sh'.format(java_path, cluster_dir),
+                shell=True, check=True)
+            subprocess.run(
+                """echo 'export HADOOP_CLASSPATH="$HADOOP_HOME/share/hadoop/tools/lib/*"' >> {}hadoop/etc/hadoop/hadoop-env.sh""".format(
+                    cluster_dir), shell=True, check=True)
+            subprocess.run('echo "export HADOOP_HOME={0}hadoop/" >> {0}spark/conf/spark-env.sh'.format(cluster_dir),
+                           shell=True, check=True)
+            subprocess.run('echo "export SPARK_HOME={0}spark/" >> {0}spark/conf/spark-env.sh'.format(cluster_dir),
+                           shell=True, check=True)
+            spark_dist_classpath = subprocess.run('{}hadoop/bin/hadoop classpath'.format(cluster_dir),
+                                                  capture_output=True, shell=True, check=True).stdout.decode(
+                'UTF-8').rstrip("\n\r")
             subprocess.run('echo "export SPARK_DIST_CLASSPATH={}" >> {}spark/conf/spark-env.sh'.format(
                 spark_dist_classpath, cluster_dir), shell=True, check=True)
     except:
diff --git a/infrastructure-provisioning/src/general/lib/azure/meta_lib.py b/infrastructure-provisioning/src/general/lib/azure/meta_lib.py
index 510e875..dd595e5 100644
--- a/infrastructure-provisioning/src/general/lib/azure/meta_lib.py
+++ b/infrastructure-provisioning/src/general/lib/azure/meta_lib.py
@@ -20,17 +20,16 @@
 # ******************************************************************************
 
 from azure.common.client_factory import get_client_from_auth_file
-from azure.mgmt.authorization import AuthorizationManagementClient
 from azure.mgmt.compute import ComputeManagementClient
 from azure.mgmt.resource import ResourceManagementClient
 from azure.mgmt.network import NetworkManagementClient
 from azure.mgmt.storage import StorageManagementClient
-from azure.storage.blob import BlockBlobService
+from azure.storage.blob import BlobServiceClient
 from azure.mgmt.datalake.store import DataLakeStoreAccountManagementClient
 from azure.datalake.store import core, lib
-from azure.graphrbac import GraphRbacManagementClient
-from azure.common.credentials import ServicePrincipalCredentials
-import azure.common.exceptions as AzureExceptions
+from azure.identity import ClientSecretCredential
+from azure.core.exceptions import ResourceNotFoundError
+from azure.mgmt.hdinsight import HDInsightManagementClient
 import logging
 import traceback
 import sys
@@ -40,25 +39,64 @@
 
 class AzureMeta:
     def __init__(self):
-
         os.environ['AZURE_AUTH_LOCATION'] = '/root/azure_auth.json'
-        self.compute_client = get_client_from_auth_file(ComputeManagementClient)
-        self.resource_client = get_client_from_auth_file(ResourceManagementClient)
-        self.network_client = get_client_from_auth_file(NetworkManagementClient)
-        self.storage_client = get_client_from_auth_file(StorageManagementClient)
-        self.datalake_client = get_client_from_auth_file(DataLakeStoreAccountManagementClient)
-        #self.authorization_client = get_client_from_auth_file(AuthorizationManagementClient)
+        with open('/root/azure_auth.json') as json_file:
+            json_dict = json.load(json_file)
+
+        credential = ClientSecretCredential(
+            tenant_id=json_dict["tenantId"],
+            client_id=json_dict["clientId"],
+            client_secret=json_dict["clientSecret"],
+            authority=json_dict["activeDirectoryEndpointUrl"]
+        )
+
+        self.compute_client = ComputeManagementClient(
+            credential,
+            json_dict["subscriptionId"],
+            base_url=json_dict["resourceManagerEndpointUrl"],
+            credential_scopes=["{}/.default".format(json_dict["resourceManagerEndpointUrl"])]
+        )
+        self.resource_client = ResourceManagementClient(
+            credential,
+            json_dict["subscriptionId"],
+            base_url=json_dict["resourceManagerEndpointUrl"],
+            credential_scopes=["{}/.default".format(json_dict["resourceManagerEndpointUrl"])]
+        )
+        self.network_client = NetworkManagementClient(
+            credential,
+            json_dict["subscriptionId"],
+            base_url=json_dict["resourceManagerEndpointUrl"],
+            credential_scopes=["{}/.default".format(json_dict["resourceManagerEndpointUrl"])]
+        )
+        self.storage_client = StorageManagementClient(
+            credential,
+            json_dict["subscriptionId"],
+            base_url=json_dict["resourceManagerEndpointUrl"],
+            credential_scopes=["{}/.default".format(json_dict["resourceManagerEndpointUrl"])]
+        )
+        self.datalake_client = DataLakeStoreAccountManagementClient(
+            credential,
+            json_dict["subscriptionId"],
+            base_url=json_dict["resourceManagerEndpointUrl"]
+        )
+        self.hdinsight_client = HDInsightManagementClient(
+            credential,
+            json_dict["subscriptionId"],
+            base_url=json_dict["resourceManagerEndpointUrl"]
+        )
         self.sp_creds = json.loads(open(os.environ['AZURE_AUTH_LOCATION']).read())
         self.dl_filesystem_creds = lib.auth(tenant_id=json.dumps(self.sp_creds['tenantId']).replace('"', ''),
                                             client_secret=json.dumps(self.sp_creds['clientSecret']).replace('"', ''),
                                             client_id=json.dumps(self.sp_creds['clientId']).replace('"', ''),
                                             resource='https://datalake.azure.net/')
+        logger = logging.getLogger('azure')
+        logger.setLevel(logging.ERROR)
 
     def get_resource_group(self, resource_group_name):
         try:
             result = self.resource_client.resource_groups.get(resource_group_name)
             return result
-        except AzureExceptions.CloudError as err:
+        except ResourceNotFoundError as err:
             if err.status_code == 404:
                 return ''
         except Exception as err:
@@ -73,7 +111,7 @@
         try:
             result = self.network_client.virtual_networks.get(resource_group_name, vpc_name)
             return result
-        except AzureExceptions.CloudError as err:
+        except ResourceNotFoundError as err:
             if err.status_code == 404:
                 return ''
         except Exception as err:
@@ -88,7 +126,7 @@
         try:
             result = self.network_client.subnets.get(resource_group_name, vpc_name, subnet_name)
             return result
-        except AzureExceptions.CloudError as err:
+        except ResourceNotFoundError as err:
             if err.status_code == 404:
                 return ''
         except Exception as err:
@@ -106,7 +144,7 @@
                 network_security_group_name
             )
             return result
-        except AzureExceptions.CloudError as err:
+        except ResourceNotFoundError as err:
             if err.status_code == 404:
                 return ''
         except Exception as err:
@@ -122,7 +160,7 @@
             result = self.network_client.security_rules.get(resource_group_name, network_security_group_name,
                                                             rule_name)
             return result
-        except AzureExceptions.CloudError as err:
+        except ResourceNotFoundError as err:
             if err.status_code == 404:
                 return ''
         except Exception as err:
@@ -137,7 +175,7 @@
         try:
             result = self.network_client.security_rules.list(resource_group_name, sg_name)
             return result
-        except AzureExceptions.CloudError as err:
+        except ResourceNotFoundError as err:
             if err.status_code == 404:
                 return ''
         except Exception as err:
@@ -152,7 +190,7 @@
         try:
             result = self.network_client.subnets.list(resource_group_name, vpc_name)
             return result
-        except AzureExceptions.CloudError as err:
+        except ResourceNotFoundError as err:
             if err.status_code == 404:
                 return ''
         except Exception as err:
@@ -167,7 +205,7 @@
         try:
             result = self.compute_client.virtual_machines.get(resource_group_name, instance_name)
             return result
-        except AzureExceptions.CloudError as err:
+        except ResourceNotFoundError as err:
             if err.status_code == 404:
                 return ''
         except Exception as err:
@@ -200,7 +238,7 @@
                 datalake_name
             )
             return result
-        except AzureExceptions.CloudError as err:
+        except ResourceNotFoundError as err:
             if err.status_code == 404:
                 return ''
         except Exception as err:
@@ -213,9 +251,9 @@
 
     def list_datalakes(self, resource_group_name):
         try:
-            result = self.datalake_client.account.list_by_resource_group(resource_group_name)
+            result = self.datalake_client.accounts.list_by_resource_group(resource_group_name)
             return result
-        except AzureExceptions.CloudError as err:
+        except ResourceNotFoundError as err:
             if err.status_code == 404:
                 return ''
         except Exception as err:
@@ -246,7 +284,7 @@
                 account_name
             )
             return result
-        except AzureExceptions.CloudError as err:
+        except ResourceNotFoundError as err:
             if err.status_code == 404:
                 return ''
         except Exception as err:
@@ -261,7 +299,7 @@
         try:
             result = self.storage_client.storage_accounts.list_by_resource_group(resource_group_name)
             return result
-        except AzureExceptions.CloudError as err:
+        except ResourceNotFoundError as err:
             if err.status_code == 404:
                 return ''
         except Exception as err:
@@ -274,7 +312,9 @@
 
     def check_account_availability(self, account_name):
         try:
-            result = self.storage_client.storage_accounts.check_name_availability(account_name)
+            result = self.storage_client.storage_accounts.check_name_availability(
+                { "name": account_name }
+            )
             return result
         except Exception as err:
             logging.info(
@@ -303,7 +343,7 @@
         try:
             result = []
             secret_key = list_storage_keys(resource_group_name, account_name)[0]
-            block_blob_service = BlockBlobService(account_name=account_name, account_key=secret_key)
+            block_blob_service = BlobServiceClient(account_url="https://" + account_name + ".blob.core.windows.net/", credential=secret_key)
             content = block_blob_service.list_blobs(container_name)
             for blob in content:
                 result.append(blob.name)
@@ -323,7 +363,7 @@
                 ip_name
             )
             return result
-        except AzureExceptions.CloudError as err:
+        except ResourceNotFoundError as err:
             if err.status_code == 404:
                 return ''
         except Exception as err:
@@ -338,7 +378,7 @@
         try:
             result = self.network_client.public_ip_addresses.list(resource_group_name)
             return result
-        except AzureExceptions.CloudError as err:
+        except ResourceNotFoundError as err:
             if err.status_code == 404:
                 return ''
         except Exception as err:
@@ -404,7 +444,7 @@
         try:
             result = self.network_client.network_interfaces.get(resource_group_name, network_interface_name)
             return result
-        except AzureExceptions.CloudError as err:
+        except ResourceNotFoundError as err:
             if err.status_code == 404:
                 return ''
         except Exception as err:
@@ -419,7 +459,7 @@
         try:
             result = self.network_client.network_interfaces.list(resource_group_name)
             return result
-        except AzureExceptions.CloudError as err:
+        except ResourceNotFoundError as err:
             if err.status_code == 404:
                 return ''
         except Exception as err:
@@ -449,7 +489,7 @@
         try:
             result = self.compute_client.disks.get(resource_group_name, disk_name)
             return result
-        except AzureExceptions.CloudError as err:
+        except ResourceNotFoundError as err:
             if err.status_code == 404:
                 return ''
         except Exception as err:
@@ -464,7 +504,7 @@
         try:
             result = self.compute_client.disks.list_by_resource_group(resource_group_name)
             return result
-        except AzureExceptions.CloudError as err:
+        except ResourceNotFoundError as err:
             if err.status_code == 404:
                 return ''
         except Exception as err:
@@ -497,6 +537,32 @@
                 data.append(host)
         return data
 
+    def get_image_statuses(self, resource_group_name, image_name_list):
+        data = []
+        for image_name in image_name_list:
+            image_name = image_name['id']
+            host = {}
+            try:
+                request = self.compute_client.images.get(resource_group_name, image_name)
+                host['id'] = image_name
+                if request.provisioning_state == 'Succeeded':
+                    host['status'] = 'ACTIVE'
+                elif request.provisioning_state == 'Deleting':
+                    host['status'] = 'TERMINATING'
+                elif request.provisioning_state == 'Canceled':
+                    host['status'] = 'FAILED'
+                elif request.provisioning_state == 'Creating':
+                    host['status'] = 'CREATING'
+                elif request.provisioning_state == 'Locked':
+                    host['status'] = 'FAILED'
+                data.append(host)
+            except:
+                host['id'] = image_name
+                host['status'] = 'TERMINATED'
+                data.append(host)
+        return data
+
+
     def get_instance_status(self, resource_group_name, instance_name):
         try:
             request = self.compute_client.virtual_machines.get(resource_group_name, instance_name, expand='instanceView')
@@ -523,7 +589,7 @@
     def get_image(self, resource_group_name, image_name):
         try:
             return self.compute_client.images.get(resource_group_name, image_name)
-        except AzureExceptions.CloudError as err:
+        except ResourceNotFoundError as err:
             if err.status_code == 404:
                 return ''
         except Exception as err:
@@ -603,6 +669,62 @@
                                    file=sys.stdout)}))
             traceback.print_exc(file=sys.stdout)
 
+    def get_hdinsight_cluster(self, resource_group_name, cluster_name):
+        try:
+            result = self.hdinsight_client.clusters.get(resource_group_name, cluster_name)
+            return result
+        except ResourceNotFoundError as err:
+            if err.status_code == 404:
+                return ''
+        except Exception as err:
+            logging.info(
+                "Unable to get hdinsight cluster: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+            append_result(str({"error": "Unable to get hdinsight cluster",
+                               "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
+                                   file=sys.stdout)}))
+            traceback.print_exc(file=sys.stdout)
+
+    def list_hdinsight_clusters(self, resource_group_name):
+        try:
+            result = self.hdinsight_client.clusters.list_by_resource_group(resource_group_name)
+            return result
+        except ResourceNotFoundError as err:
+            if err.status_code == 404:
+                return ''
+        except Exception as err:
+            logging.info(
+                "Unable to list hdinsight clusters: " + str(err) + "\n Traceback: " + traceback.print_exc(file=sys.stdout))
+            append_result(str({"error": "Unable to list hdinsight clusters",
+                               "error_message": str(err) + "\n Traceback: " + traceback.print_exc(
+                                   file=sys.stdout)}))
+            traceback.print_exc(file=sys.stdout)
+
+
+    def list_hdinsight_statuses(self, resource_group_name, cluster_name_list):
+        data = []
+        for cluster_name in cluster_name_list:
+            cluster_name = cluster_name['id']
+            host = {}
+            try:
+                request = self.hdinsight_client.clusters.get(resource_group_name, cluster_name)
+                host['id'] = cluster_name
+                if request.properties.cluster_state == 'Accepted' or request.properties.cluster_state == 'HdInsightConfiguration' or request.properties.cluster_state == 'ClusterStorageProvisioned' or request.properties.cluster_state == 'ReadyForDeployment':
+                    host['status'] = 'creating'
+                elif request.properties.cluster_state == 'AzureVMConfiguration' or request.properties.cluster_state == 'Operational' or request.properties.cluster_state == 'ClusterCustomization':
+                    host['status'] = 'creating'
+                elif request.properties.cluster_state == 'DeletePending' or request.properties.cluster_state == 'Deleting':
+                    host['status'] = 'terminating'
+                elif request.properties.cluster_state == 'Error' or request.properties.cluster_state == 'TimedOut' or request.properties.cluster_state == 'Unknown':
+                    host['status'] = 'failed'
+                elif request.properties.cluster_state == 'Running':
+                    host['status'] = 'running'
+                data.append(host)
+            except:
+                host['id'] = cluster_name
+                host['status'] = 'terminated'
+                data.append(host)
+        return data
+
 
 def get_instance_private_ip_address(tag_name, instance_name):
     try:
diff --git a/infrastructure-provisioning/src/general/lib/gcp/actions_lib.py b/infrastructure-provisioning/src/general/lib/gcp/actions_lib.py
index e4b070f..b0733b8 100644
--- a/infrastructure-provisioning/src/general/lib/gcp/actions_lib.py
+++ b/infrastructure-provisioning/src/general/lib/gcp/actions_lib.py
@@ -222,12 +222,18 @@
                                    file=sys.stdout)}))
             traceback.print_exc(file=sys.stdout)
 
-    def add_bucket_labels(self, bucket_name, tags):
+    def add_bucket_labels_vers_cmek(self, bucket_name, tags, versioning_enabled='false', cmek_resource_name='',
+                                    lifecycle_rules=''):
         try:
             bucket = self.storage_client.get_bucket(bucket_name)
             labels = bucket.labels
             labels.update(tags)
             bucket.labels = labels
+            bucket.versioning = {"enabled": versioning_enabled}
+            if cmek_resource_name != '':
+                bucket.encryption = {"defaultKmsKeyName": cmek_resource_name}
+            if lifecycle_rules != '':
+                bucket.lifecycle_rules = ast.literal_eval(lifecycle_rules)
             bucket.patch()
             print('Updated labels on {}.'.format(bucket_name))
         except Exception as err:
@@ -271,15 +277,21 @@
                                    file=sys.stdout)}))
             traceback.print_exc(file=sys.stdout)
 
-    def create_disk(self, instance_name, zone, size, secondary_image_name):
+    def create_disk(self, instance_name, zone, size, secondary_image_name, rsa_encrypted_csek=''):
         try:
             if secondary_image_name == 'None':
                 params = {"sizeGb": size, "name": instance_name + '-secondary',
                           "type": "projects/{0}/zones/{1}/diskTypes/pd-ssd".format(self.project, zone)}
+                if rsa_encrypted_csek:
+                    params['diskEncryptionKey'] = {"rsaEncryptedKey": rsa_encrypted_csek}
+
             else:
                 params = {"sizeGb": size, "name": instance_name + '-secondary',
                           "type": "projects/{0}/zones/{1}/diskTypes/pd-ssd".format(self.project, zone),
                           "sourceImage": secondary_image_name}
+                if rsa_encrypted_csek:
+                    params["sourceImageEncryptionKey"] = {"rsaEncryptedKey": rsa_encrypted_csek}
+                    params['diskEncryptionKey'] = {"rsaEncryptedKey": rsa_encrypted_csek}
             request = self.service.disks().insert(project=self.project, zone=zone, body=params)
             result = request.execute()
             datalab.meta_lib.GCPMeta().wait_for_operation(result['name'], zone=zone)
@@ -315,12 +327,12 @@
                                    file=sys.stdout)}))
             traceback.print_exc(file=sys.stdout)
 
-    def create_instance(self, instance_name, service_base_name, cluster_name, region, zone, vpc_name, subnet_name, instance_size,
-                        ssh_key_path,
-                        initial_user, image_name, secondary_image_name, service_account_name, instance_class,
-                        network_tag, labels, static_ip='',
+    def create_instance(self, instance_name, service_base_name, cluster_name, region, zone, vpc_name, subnet_name,
+                        instance_size, ssh_key_path, initial_user, image_name, secondary_image_name,
+                        service_account_name, instance_class, network_tag, labels, static_ip='',
                         primary_disk_size='12', secondary_disk_size='30',
-                        gpu_accelerator_type='None', gpu_accelerator_count='1'):
+                        gpu_accelerator_type='None', gpu_accelerator_count='1',
+                        os_login_enabled='FALSE', block_project_ssh_keys='FALSE', rsa_encrypted_csek=''):
         key = RSA.importKey(open(ssh_key_path, 'rb').read())
         ssh_key = key.publickey().exportKey("OpenSSH").decode('UTF-8')
         unique_index = datalab.meta_lib.GCPMeta().get_index_by_service_account_name(service_account_name)
@@ -337,7 +349,7 @@
                 "natIP": static_ip
             }]
         if instance_class == 'notebook':
-            GCPActions().create_disk(instance_name, zone, secondary_disk_size, secondary_image_name)
+            GCPActions().create_disk(instance_name, zone, secondary_disk_size, secondary_image_name, rsa_encrypted_csek)
             disks = [
                 {
                     "name": instance_name,
@@ -367,7 +379,7 @@
                 }
             ]
         elif instance_class == 'dataengine':
-            GCPActions().create_disk(instance_name, zone, secondary_disk_size, secondary_image_name)
+            GCPActions().create_disk(instance_name, zone, secondary_disk_size, secondary_image_name, rsa_encrypted_csek)
             disks = [{
                 "name": instance_name,
                 "tag_name": cluster_name + '-volume-primary',
@@ -407,6 +419,16 @@
                 "boot": 'true',
                 "mode": "READ_WRITE"
             }]
+
+        if service_base_name in image_name and rsa_encrypted_csek:
+            for disk in disks:
+                if "initializeParams" in disk:
+                    disk["initializeParams"]["sourceImageEncryptionKey"] = {"rsaEncryptedKey": rsa_encrypted_csek}
+                disk["diskEncryptionKey"] = {"rsaEncryptedKey": rsa_encrypted_csek}
+        elif rsa_encrypted_csek:
+            for disk in disks:
+                disk["diskEncryptionKey"] = {"rsaEncryptedKey": rsa_encrypted_csek}
+
         instance_params = {
             "name": instance_name,
             "machineType": "zones/{}/machineTypes/{}".format(zone, instance_size),
@@ -424,6 +446,14 @@
                     {
                         "key": "ssh-keys",
                         "value": "{}:{}".format(initial_user, ssh_key)
+                    },
+                    {
+                        "key": "enable-oslogin",
+                        "value": "{}".format(os_login_enabled)
+                    },
+                    {
+                        "key": "block-project-ssh-keys",
+                        "value": "{}".format(block_project_ssh_keys)
                     }
                 ]
                 },
@@ -537,8 +567,18 @@
                                    file=sys.stdout)}))
             traceback.print_exc(file=sys.stdout)
 
-    def start_instance(self, instance_name, zone):
-        request = self.service.instances().start(project=self.project, zone=zone, instance=instance_name)
+    def start_instance(self, instance_name, zone, rsa_encrypted_csek=''):
+        if rsa_encrypted_csek:
+            params = dict()
+            params['disks'] = list()
+            instance_data = datalab.meta_lib.GCPMeta().get_instance(instance_name)
+            for disk in instance_data['disks']:
+                params["disks"].append(
+                    {"diskEncryptionKey": {"rsaEncryptedKey": rsa_encrypted_csek}, "source": disk['source']})
+            request = self.service.instances().startWithEncryptionKey(project=self.project, zone=zone,
+                                                                      instance=instance_name, body=params)
+        else:
+            request = self.service.instances().start(project=self.project, zone=zone, instance=instance_name)
         try:
             result = request.execute()
             datalab.meta_lib.GCPMeta().wait_for_operation(result['name'], zone=zone)
@@ -792,21 +832,28 @@
                                    file=sys.stdout)}))
             traceback.print_exc(file=sys.stdout)
 
-    def create_image_from_instance_disks(self, primary_image_name, secondary_image_name, instance_name, zone, labels):
+    def create_image_from_instance_disks(self, primary_image_name, secondary_image_name, instance_name, zone, labels,
+                                         rsa_encrypted_csek=''):
         primary_disk_name = "projects/{0}/zones/{1}/disks/{2}".format(self.project, zone, instance_name)
         secondary_disk_name = "projects/{0}/zones/{1}/disks/{2}-secondary".format(self.project, zone, instance_name)
         labels.update({"name": primary_image_name})
         primary_params = {"name": primary_image_name, "sourceDisk": primary_disk_name, "labels": labels}
+        if rsa_encrypted_csek:
+            primary_params["imageEncryptionKey"] = {"rsaEncryptedKey": rsa_encrypted_csek}
+            primary_params["sourceDiskEncryptionKey"] = {"rsaEncryptedKey": rsa_encrypted_csek}
         primary_request = self.service.images().insert(project=self.project, body=primary_params)
         labels.update({"name": secondary_image_name})
         secondary_params = {"name": secondary_image_name, "sourceDisk": secondary_disk_name, "labels": labels}
+        if rsa_encrypted_csek:
+            secondary_params["imageEncryptionKey"] = {"rsaEncryptedKey": rsa_encrypted_csek}
+            secondary_params["sourceDiskEncryptionKey"] = {"rsaEncryptedKey": rsa_encrypted_csek}
         secondary_request = self.service.images().insert(project=self.project, body=secondary_params)
-        id_list=[]
+        id_list = []
         try:
             GCPActions().stop_instance(instance_name, zone)
             primary_image_check = datalab.meta_lib.GCPMeta().get_image_by_name(primary_image_name)
             if primary_image_check != '':
-                GCPActions().start_instance(instance_name, zone)
+                GCPActions().start_instance(instance_name, zone, rsa_encrypted_csek)
                 return ''
             primary_result = primary_request.execute()
             secondary_result = secondary_request.execute()
@@ -816,7 +863,7 @@
             datalab.meta_lib.GCPMeta().wait_for_operation(secondary_result['name'])
             print('Image {} has been created.'.format(secondary_image_name))
             id_list.append(secondary_result.get('id'))
-            GCPActions().start_instance(instance_name, zone)
+            GCPActions().start_instance(instance_name, zone, rsa_encrypted_csek)
             return id_list
         except Exception as err:
             logging.info(
@@ -1293,7 +1340,7 @@
         except:
             sys.exit(1)
 
-    def install_python(self, bucket, user_name, cluster_name, application, numpy_version='1.14.3'):
+    def install_python(self, bucket, user_name, cluster_name, application, numpy_version):
         try:
             GCPActions().get_cluster_app_version(bucket, user_name, cluster_name, 'python')
             with open('/tmp/python_version') as f:
@@ -1308,15 +1355,14 @@
                 subprocess.run('sudo -i virtualenv /opt/python/python{}'.format(python_version), shell=True, check=True)
                 venv_command = 'source /opt/python/python{}/bin/activate'.format(python_version)
                 pip_command = '/opt/python/python{0}/bin/pip{1}'.format(python_version, python_version[:3])
-                subprocess.run('{0} && sudo -i {1} install -U pip==9.0.3'.format(venv_command, pip_command), shell=True, check=True)
-                subprocess.run('{0} && sudo -i {1} install pyzmq==17.0.0'.format(venv_command, pip_command), shell=True, check=True)
-                subprocess.run('{0} && sudo -i {1} install ipython ipykernel --no-cache-dir'.format(venv_command, pip_command), shell=True, check=True)
-                subprocess.run('{0} && sudo -i {1} install boto boto3 NumPy=={2} SciPy Matplotlib pandas Sympy Pillow sklearn --no-cache-dir'
-                      .format(venv_command, pip_command, numpy_version), shell=True, check=True)
+                for lib in ['-U pip==9.0.3', 'pyzmq==17.0.0', 'ipython ipykernel boto boto3 pybind11 pythran cython NumPy=={} Matplotlib --no-cache-dir'.format(numpy_version),
+                            'SciPy pandas Sympy Pillow --no-cache-dir', 'sklearn --no-cache-dir']:
+                    subprocess.run('bash -c "{0} && sudo -i {1} install {2}"'
+                                   .format(venv_command, pip_command, lib), shell=True, check=True)
                 if application == 'deeplearning':
-                    subprocess.run('{0} && sudo -i {1} install mxnet-cu80 opencv-python keras Theano --no-cache-dir'.format(venv_command, pip_command), shell=True, check=True)
+                    subprocess.run('bash -c "{0} && sudo -i {1} install mxnet-cu80 opencv-python keras Theano --no-cache-dir"'.format(venv_command, pip_command), shell=True, check=True)
                     python_without_dots = python_version.replace('.', '')
-                    subprocess.run('{0} && sudo -i {1} install  https://cntk.ai/PythonWheel/GPU/cntk-2.0rc3-cp{2}-cp{2}m-linux_x86_64.whl --no-cache-dir'
+                    subprocess.run('bash -c "{0} && sudo -i {1} install  https://cntk.ai/PythonWheel/GPU/cntk-2.0rc3-cp{2}-cp{2}m-linux_x86_64.whl --no-cache-dir"'
                           .format(venv_command, pip_command, python_without_dots[:2]), shell=True, check=True)
                 subprocess.run('sudo rm -rf /usr/bin/python{}-dp'.format(python_version[0:3]), shell=True, check=True)
                 subprocess.run('sudo ln -fs /opt/python/python{0}/bin/python{1} /usr/bin/python{1}-dp'.format(python_version, python_version[0:3]), shell=True, check=True)
@@ -1362,7 +1408,7 @@
 
 def installing_python(region, bucket, user_name, cluster_name, application='', pip_mirror='', numpy_version='1.14.3'):
     try:
-        GCPActions().install_python(bucket, user_name, cluster_name, application)
+        GCPActions().install_python(bucket, user_name, cluster_name, application, numpy_version)
     except:
         sys.exit(1)
 
diff --git a/infrastructure-provisioning/src/general/lib/gcp/meta_lib.py b/infrastructure-provisioning/src/general/lib/gcp/meta_lib.py
index be5d17b..c19af98 100644
--- a/infrastructure-provisioning/src/general/lib/gcp/meta_lib.py
+++ b/infrastructure-provisioning/src/general/lib/gcp/meta_lib.py
@@ -673,6 +673,27 @@
                 data.append(host)
         return data
 
+    def get_list_image_statuses(self, image_name_list):
+        data = []
+        for image in image_name_list:
+            host = {}
+            try:
+                request = self.service.images().get(project=self.project, image=image)
+                result = request.execute()
+                host['id'] = image
+                if result.get('status') == 'PENDING':
+                    host['status'] = 'CREATING'
+                elif result.get('status') == 'READY':
+                    host['status'] = 'ACTIVE'
+                else:
+                    host['status'] = result.get('status')
+                data.append(host)
+            except:
+                host['id'] = image
+                host['status'] = 'TERMINATED'
+                data.append(host)
+        return data
+
     def get_cluster(self, cluster_name):
         try:
             request = self.dataproc.projects().regions().clusters().get(projectId=self.project,
@@ -758,7 +779,7 @@
 
     def dataproc_waiter(self, labels):
         if os.path.exists(
-                '/response/.emr_creating_' + os.environ['exploratory_name']) or self.get_not_configured_dataproc(
+                '/response/.dataproc_creating_' + os.environ['exploratory_name']) or self.get_not_configured_dataproc(
                 os.environ['notebook_instance_name']):
             with hide('stderr', 'running', 'warnings'):
                 subprocess.run("echo 'Some Dataproc cluster is still being created/terminated, waiting..'", shell=True, check=True)
diff --git a/infrastructure-provisioning/src/general/lib/os/debian/common_lib.py b/infrastructure-provisioning/src/general/lib/os/debian/common_lib.py
index dc4920c..91d9bed 100644
--- a/infrastructure-provisioning/src/general/lib/os/debian/common_lib.py
+++ b/infrastructure-provisioning/src/general/lib/os/debian/common_lib.py
@@ -223,10 +223,9 @@
         sys.exit(1)
 
 
-def ensure_pkg(os_user, requisites='linux-headers-$(uname -r) python3-pip python3-dev python3-virtualenv '
-                                'groff gcc vim less git wget '
-                                'libssl-dev unattended-upgrades nmap '
-                                'libffi-dev unzip libxml2-dev haveged'):
+def ensure_pkg(os_user, requisites='linux-headers-$(uname -r) python3-pip python3-opencv python3-dev '
+                                   'python3-virtualenv groff gcc vim less git wget libssl-dev unattended-upgrades '
+                                   'nmap libffi-dev unzip libxml2-dev haveged'):
     try:
         if not exists(datalab.fab.conn,'/home/{}/.ensure_dir/pkg_upgraded'.format(os_user)):
             count = 0
@@ -285,11 +284,12 @@
         sys.exit(1)
 
 
-def disable_edge_scp_binary(os_user):
+def remove_scp_nmap_binary(os_user):
     try:
-        if not exists(datalab.fab.conn, '/home/{}/.ensure_dir/disabled_scp_binary'.format(os_user)):
-            datalab.fab.conn.sudo('mv /usr/bin/scp /usr/bin/scp_disabled')
-        datalab.fab.conn.sudo('touch /home/{}/.ensure_dir/disabled_scp_binary'.format(os_user))
+        if not exists(datalab.fab.conn, '/home/{}/.ensure_dir/remove_scp_nmap_binary'.format(os_user)):
+            datalab.fab.conn.sudo('rm /usr/bin/scp')
+            datalab.fab.conn.sudo('rm /usr/share/nmap/nselib/data/psexec/nmap_service.exe > /dev/null; echo $?')
+        datalab.fab.conn.sudo('touch /home/{}/.ensure_dir/remove_scp_nmap_binary'.format(os_user))
     except Exception as err:
         logging.error('Updating openssh to version:', str(err))
         traceback.print_exc()
diff --git a/infrastructure-provisioning/src/general/lib/os/debian/edge_lib.py b/infrastructure-provisioning/src/general/lib/os/debian/edge_lib.py
index 34d1273..e127d4a 100644
--- a/infrastructure-provisioning/src/general/lib/os/debian/edge_lib.py
+++ b/infrastructure-provisioning/src/general/lib/os/debian/edge_lib.py
@@ -92,7 +92,7 @@
             datalab.fab.conn.sudo('wget -O - https://openresty.org/package/pubkey.gpg | sudo apt-key add -')
             datalab.fab.conn.sudo('add-apt-repository -y "deb http://openresty.org/package/ubuntu $(lsb_release -sc) main"')
             datalab.fab.conn.sudo('apt-get update')
-            datalab.fab.conn.sudo('apt-get -y install openresty=1.19.3.1-1~focal1')
+            datalab.fab.conn.sudo('apt-get -y install openresty={}'.format(os.environ['edge_openresty_version']))
 
             datalab.fab.conn.sudo('''bash -c 'cd /tmp/src/luarocks-3.3.1/ && ./configure' ''')
             datalab.fab.conn.sudo('''bash -c 'cd /tmp/src/luarocks-3.3.1/ && make install' ''')
diff --git a/infrastructure-provisioning/src/general/lib/os/debian/notebook_lib.py b/infrastructure-provisioning/src/general/lib/os/debian/notebook_lib.py
index 3f6ad1e..0f1143b 100644
--- a/infrastructure-provisioning/src/general/lib/os/debian/notebook_lib.py
+++ b/infrastructure-provisioning/src/general/lib/os/debian/notebook_lib.py
@@ -85,9 +85,11 @@
             r_repository = 'https://cloud.r-project.org'
             #add_marruter_key()
             datalab.fab.conn.sudo('apt update')
-            manage_pkg('-yV install', 'remote', 'libssl-dev libcurl4-gnutls-dev libgit2-dev libxml2-dev libreadline-dev')
+            manage_pkg('-yV install', 'remote', 'libfreetype6-dev libpng-dev libtiff5-dev libjpeg-dev '
+                                                'libfontconfig1-dev libharfbuzz-dev libfribidi-dev libssl-dev '
+                                                'libcurl4-gnutls-dev libgit2-dev libxml2-dev libreadline-dev')
             manage_pkg('-y install', 'remote', 'cmake')
-            datalab.fab.conn.sudo('''bash -c -l 'apt-key adv --keyserver-options http-proxy="$http_proxy" --keyserver hkp://keyserver.ubuntu.com --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9' ''')
+            datalab.fab.conn.sudo('''bash -c -l 'apt-key adv --keyserver-options http-proxy="$http_proxy" --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9' ''')
             datalab.fab.conn.sudo("add-apt-repository 'deb https://cloud.r-project.org/bin/linux/ubuntu focal-cran40/'")
             manage_pkg('update', 'remote', '')
             manage_pkg('-y install', 'remote', 'r-base r-base-dev')
@@ -213,7 +215,7 @@
     if not exists(datalab.fab.conn,'/home/' + os_user + '/.ensure_dir/scala_ensured'):
         try:
             datalab.fab.conn.sudo('hostname; pwd')
-            datalab.fab.conn.sudo('wget {}scala-{}.deb --tries=3 -O /tmp/scala.deb'.format(scala_link, scala_version))
+            datalab.fab.conn.sudo('wget {}scala-{}.deb --tries=5 -O /tmp/scala.deb'.format(scala_link, scala_version))
             datalab.fab.conn.sudo('dpkg -i /tmp/scala.deb')
             datalab.fab.conn.sudo('touch /home/' + os_user + '/.ensure_dir/scala_ensured')
         except:
@@ -248,6 +250,7 @@
                 datalab.fab.conn.sudo('pip3 install NumPy=={} SciPy pandas Sympy Pillow sklearn --no-cache-dir'.format(os.environ['notebook_numpy_version']))
             if os.environ['application'] in ('tensor', 'deeplearning'):
                 datalab.fab.conn.sudo('pip3 install opencv-python h5py --no-cache-dir')
+                #datalab.fab.conn.sudo('pip3 install python3-opencv scikit-learn --no-cache-dir')
             datalab.fab.conn.sudo('touch /home/' + os_user + '/.ensure_dir/additional_python_libs_ensured')
         except:
             sys.exit(1)
@@ -270,22 +273,41 @@
             #manage_pkg('-y install', 'remote', 'python3-setuptools')
             manage_pkg('-y install', 'remote', 'python3-pip')
             manage_pkg('-y install', 'remote', 'libkrb5-dev')
-            datalab.fab.conn.sudo('pip3 install -U keyrings.alt backoff')
-            if os.environ['conf_cloud_provider'] == 'aws' and os.environ['conf_deeplearning_cloud_ami'] == 'true': 
-                datalab.fab.conn.sudo('pip3 install --upgrade --user pyqt5==5.12')
-                datalab.fab.conn.sudo('pip3 install --upgrade --user pyqtwebengine==5.12')
-                datalab.fab.conn.sudo('pip3 install setuptools')
-            else:
+            manage_pkg('-y install', 'remote', 'libbz2-dev libsqlite3-dev tk-dev libncursesw5-dev libreadline-dev '
+                                               'liblzma-dev uuid-dev lzma-dev libgdbm-dev')  #necessary for python build
+            if os.environ['conf_cloud_provider'] == 'aws' and os.environ['conf_deeplearning_cloud_ami'] == 'true':
+                datalab.fab.conn.sudo('-i pip3 install -U keyrings.alt backoff')
+                datalab.fab.conn.sudo('-i pip3 install --upgrade --user pyqt5==5.12')
+                datalab.fab.conn.sudo('-i pip3 install --upgrade --user pyqtwebengine==5.12')
                 datalab.fab.conn.sudo('pip3 install setuptools=={}'.format(os.environ['notebook_setuptools_version']))
-            try:
-                datalab.fab.conn.sudo('pip3 install tornado=={0} ipython==7.21.0 ipykernel=={1} sparkmagic --no-cache-dir' \
-                     .format(os.environ['notebook_tornado_version'], os.environ['notebook_ipykernel_version']))
-            except:
-                datalab.fab.conn.sudo('pip3 install tornado=={0} ipython==7.9.0 ipykernel=={1} sparkmagic --no-cache-dir' \
-                     .format(os.environ['notebook_tornado_version'], os.environ['notebook_ipykernel_version']))
-            datalab.fab.conn.sudo('pip3 install -U pip=={} --no-cache-dir'.format(os.environ['conf_pip_version']))
-            datalab.fab.conn.sudo('pip3 install boto3 --no-cache-dir')
-            datalab.fab.conn.sudo('pip3 install fabvenv fabric-virtualenv future patchwork --no-cache-dir')
+                try:
+                    datalab.fab.conn.sudo(
+                        '-i pip3 install tornado=={0} ipython==7.21.0 ipykernel=={1} nbconvert=={2} nbformat=={3} sparkmagic --no-cache-dir' \
+                        .format(os.environ['notebook_tornado_version'], os.environ['notebook_ipykernel_version'],
+                                os.environ['notebook_nbconvert_version'], os.environ['notebook_nbformat_version']))
+                except:
+                    datalab.fab.conn.sudo(
+                        '-i pip3 install tornado=={0} ipython==7.9.0 ipykernel=={1} nbconvert=={2} nbformat=={3} sparkmagic --no-cache-dir' \
+                        .format(os.environ['notebook_tornado_version'], os.environ['notebook_ipykernel_version'],
+                                os.environ['notebook_nbconvert_version'], os.environ['notebook_nbformat_version']))
+                datalab.fab.conn.sudo(
+                    '-i pip3 install -U pip=={} --no-cache-dir'.format(os.environ['conf_pip_version']))
+                datalab.fab.conn.sudo('-i pip3 install boto3 --no-cache-dir')
+                datalab.fab.conn.sudo('-i pip3 install fabvenv fabric-virtualenv future patchwork --no-cache-dir')
+            else:
+                datalab.fab.conn.sudo('pip3 install -U keyrings.alt backoff')
+                datalab.fab.conn.sudo('pip3 install setuptools=={}'.format(os.environ['notebook_setuptools_version']))
+                try:
+                    datalab.fab.conn.sudo('pip3 install tornado=={0} ipython==7.21.0 ipykernel=={1} nbconvert=={2} nbformat=={3} sparkmagic --no-cache-dir' \
+                         .format(os.environ['notebook_tornado_version'], os.environ['notebook_ipykernel_version'],
+                                 os.environ['notebook_nbconvert_version'], os.environ['notebook_nbformat_version']))
+                except:
+                    datalab.fab.conn.sudo('pip3 install tornado=={0} ipython==7.9.0 ipykernel=={1} nbconvert=={2} nbformat=={3} sparkmagic --no-cache-dir' \
+                         .format(os.environ['notebook_tornado_version'], os.environ['notebook_ipykernel_version'],
+                                 os.environ['notebook_nbconvert_version'], os.environ['notebook_nbformat_version']))
+                datalab.fab.conn.sudo('pip3 install -U pip=={} --no-cache-dir'.format(os.environ['conf_pip_version']))
+                datalab.fab.conn.sudo('pip3 install boto3 --no-cache-dir')
+                datalab.fab.conn.sudo('pip3 install fabvenv fabric-virtualenv future patchwork --no-cache-dir')
             datalab.fab.conn.sudo('touch /home/' + os_user + '/.ensure_dir/python3_libraries_ensured')
         except:
             sys.exit(1)
@@ -293,18 +315,27 @@
 def install_nvidia_drivers(os_user):
     if not exists(datalab.fab.conn,'/home/{}/.ensure_dir/nvidia_ensured'.format(os_user)):
         try:
+            if os.environ['conf_cloud_provider'] == 'aws':
+                cuda_version = '11.3.0'
+                cuda_file_name = "cuda-repo-ubuntu2004-11-3-local_11.3.0-465.19.01-1_amd64.deb"
+                cuda_key = '/var/cuda-repo-ubuntu2004-11-3-local/7fa2af80.pub'
+            else:
+                cuda_version = '11.4.0'
+                cuda_file_name = 'cuda-repo-ubuntu2004-11-4-local_11.4.0-470.42.01-1_amd64.deb'
+                cuda_key = '/var/cuda-repo-ubuntu2004-11-4-local/7fa2af80.pub'
             # install nvidia drivers
             datalab.fab.conn.sudo(
                 'wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2004/x86_64/cuda-ubuntu2004.pin')
             datalab.fab.conn.sudo('mv cuda-ubuntu2004.pin /etc/apt/preferences.d/cuda-repository-pin-600')
             datalab.fab.conn.sudo(
-                'wget https://developer.download.nvidia.com/compute/cuda/11.4.0/local_installers/cuda-repo-ubuntu2004-11-4-local_11.4.0-470.42.01-1_amd64.deb')
-            datalab.fab.conn.sudo('dpkg -i cuda-repo-ubuntu2004-11-4-local_11.4.0-470.42.01-1_amd64.deb')
-            datalab.fab.conn.sudo('apt-key add /var/cuda-repo-ubuntu2004-11-4-local/7fa2af80.pub')
+                'wget https://developer.download.nvidia.com/compute/cuda/{}/local_installers/{}'.format(cuda_version, cuda_file_name))
+            datalab.fab.conn.sudo('dpkg -i {}'.format(cuda_file_name))
+            datalab.fab.conn.sudo('apt-key add {}'.format(cuda_key))
             manage_pkg('update', 'remote', '')
             manage_pkg('-y install', 'remote', 'cuda')
             #clean space on disk
             manage_pkg('clean', 'remote', 'all')
+            datalab.fab.conn.sudo('rm {}'.format(cuda_file_name))
             datalab.fab.conn.sudo('touch /home/{}/.ensure_dir/nvidia_ensured'.format(os_user))
         except Exception as err:
             print('Failed to install_nvidia_drivers: ', str(err))
@@ -386,6 +417,29 @@
             sys.exit(1)
 
 
+def ensure_venv_libs(os_user, libs):
+    if not exists(datalab.fab.conn, '/home/' + os_user + '/.ensure_dir/venv_libs_ensured'):
+        datalab.fab.install_venv_pip_pkg(libs)
+        datalab.fab.conn.sudo('touch /home/' + os_user + '/.ensure_dir/venv_libs_ensured')
+
+
+def ensure_pytorch(os_user, gpu=True):
+    if not exists(datalab.fab.conn, '/home/' + os_user + '/.ensure_dir/pytorch_ensured'):
+        if gpu:
+            if os.environ['application'] in ('jupyter-gpu', 'jupyter-conda'):
+                datalab.fab.install_venv_pip_pkg('torch==1.10.0+cu111 torchvision==0.11.0+cu111 '
+                                                 'torchaudio==0.10.0+cu111 -f '
+                                                 'https://download.pytorch.org/whl/cu111/torch_stable.html')
+            else:
+                datalab.fab.install_venv_pip_pkg('torch==1.10.2+cu113 torchvision==0.11.3+cu113 '
+                                                  'torchaudio==0.10.2+cu113 -f '
+                                                  'https://download.pytorch.org/whl/cu113/torch_stable.html')
+        else:
+            datalab.fab.install_venv_pip_pkg('torch==1.10.2+cpu torchvision==0.11.3+cpu torchaudio==0.10.2+cpu -f '
+                                                  'https://download.pytorch.org/whl/cpu/torch_stable.html')
+        datalab.fab.conn.sudo('touch /home/' + os_user + '/.ensure_dir/pytorch_ensured')
+
+
 def install_maven(os_user):
     if not exists(datalab.fab.conn,'/home/' + os_user + '/.ensure_dir/maven_ensured'):
         manage_pkg('-y install', 'remote', 'maven')
@@ -422,8 +476,13 @@
     if not exists(datalab.fab.conn,'/home/{}/.ensure_dir/nodejs_ensured'.format(os_user)):
         if os.environ['conf_cloud_provider'] == 'gcp' and os.environ['application'] == 'deeplearning':
             datalab.fab.conn.sudo('add-apt-repository --remove ppa:deadsnakes/ppa -y')
-        datalab.fab.conn.sudo('curl -sL https://deb.nodesource.com/setup_15.x | sudo -E bash -')
-        manage_pkg('-y install', 'remote', 'nodejs')
+        #datalab.fab.conn.sudo('bash -c "curl --silent --location https://deb.nodesource.com/setup_16.x | bash -"')
+        #manage_pkg('-y install', 'remote', 'nodejs')
+        datalab.fab.conn.sudo(
+            'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash')
+        datalab.fab.conn.run(
+            'export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" && nvm install 16.15.0')
+        datalab.fab.conn.sudo('cp -R .nvm/versions/node/v16.15.0/* /usr/')
         datalab.fab.conn.sudo('touch /home/{}/.ensure_dir/nodejs_ensured'.format(os_user))
 
 def install_os_pkg(requisites):
@@ -529,11 +588,11 @@
                    'libgtest-dev libiomp-dev libleveldb-dev liblmdb-dev '
                    'libopencv-dev libopenmpi-dev libsnappy-dev openmpi-bin openmpi-doc python-pydot')
         datalab.fab.conn.sudo(
-            'pip3 install flask graphviz hypothesis jupyter matplotlib=={} pydot python-nvd3 pyyaml requests scikit-image '
+            '-i pip3 install flask graphviz hypothesis jupyter matplotlib=={} pydot python-nvd3 pyyaml requests scikit-image '
             'scipy tornado --no-cache-dir'.format(os.environ['notebook_matplotlib_version']))
         if os.environ['application'] == 'deeplearning':
-            datalab.fab.conn.sudo('apt install -y cmake')
-            datalab.fab.conn.sudo('pip3 install torch==1.5.1+cu101 torchvision==0.6.1+cu101 -f https://download.pytorch.org/whl/torch_stable.html')
+            manage_pkg('-y install', 'remote', 'cmake')
+            datalab.fab.conn.sudo('-i pip3 install torch==1.5.1+cu101 torchvision==0.6.1+cu101 -f https://download.pytorch.org/whl/torch_stable.html')
         else:
             # datalab.fab.conn.sudo('mkdir /opt/cuda-{}'.format(os.environ['notebook_cuda_version']))
             # datalab.fab.conn.sudo('mkdir /opt/cuda-{}/include/'.format(os.environ['notebook_cuda_version']))
@@ -573,7 +632,7 @@
 
 def install_mxnet(os_user, mxnet_version):
     if not exists(datalab.fab.conn,'/home/{}/.ensure_dir/mxnet_ensured'.format(os_user)):
-        datalab.fab.conn.sudo('pip3 install mxnet-cu101=={} opencv-python --no-cache-dir'.format(mxnet_version))
+        datalab.fab.conn.sudo('-i pip3 install mxnet-cu101=={} opencv-python --no-cache-dir'.format(mxnet_version))
         datalab.fab.conn.sudo('touch /home/{}/.ensure_dir/mxnet_ensured'.format(os_user))
 
 
diff --git a/infrastructure-provisioning/src/general/lib/os/debian/ssn_lib.py b/infrastructure-provisioning/src/general/lib/os/debian/ssn_lib.py
index 5439abc..067a269 100644
--- a/infrastructure-provisioning/src/general/lib/os/debian/ssn_lib.py
+++ b/infrastructure-provisioning/src/general/lib/os/debian/ssn_lib.py
@@ -189,7 +189,7 @@
              application_id, hostname, data_lake_name, subscription_id,
              validate_permission_scope, datalab_id, usage_date, product,
              usage_type, usage, cost, resource_id, tags, billing_dataset_name, keycloak_client_id,
-             keycloak_client_secret, keycloak_auth_server_url, report_path=''):
+             keycloak_client_secret, keycloak_auth_server_url, keycloak_realm_name, report_path=''):
     try:
         if not exists(datalab.fab.conn,os.environ['ssn_datalab_path'] + 'tmp/ss_started'):
             java_path = datalab.fab.conn.sudo("update-alternatives --query java | grep 'Value: ' | grep -o '/.*/jre'").stdout.replace('\n','')
@@ -270,7 +270,7 @@
                 append_result("Unable to upload webapp jars")
                 sys.exit(1)
             if billing_enabled:
-                datalab.fab.conn.local('scp -i {} /root/scripts/configure_billing.py {}:/tmp/configure_billing.py'.format(keyfile,
+                datalab.fab.conn.local('rsync -e "ssh -i {}" /root/scripts/configure_billing.py {}:/tmp/configure_billing.py'.format(keyfile,
                                                                                                          host_string))
                 params = '--cloud_provider {} ' \
                          '--infrastructure_tag {} ' \
@@ -303,7 +303,8 @@
                          '--keystore_password {} ' \
                          '--keycloak_client_id {} ' \
                          '--keycloak_client_secret {} ' \
-                         '--keycloak_auth_server_url {} '.\
+                         '--keycloak_auth_server_url {} ' \
+                         '--keycloak_realm_name {} '. \
                             format(cloud_provider,
                                    service_base_name,
                                    tag_resource_id,
@@ -333,7 +334,8 @@
                                    keystore_passwd,
                                    keycloak_client_id,
                                    keycloak_client_secret,
-                                   keycloak_auth_server_url)
+                                   keycloak_auth_server_url,
+                                   keycloak_realm_name)
                 datalab.fab.conn.sudo('python3 /tmp/configure_billing.py {}'.format(params))
             try:
                 if os.environ['conf_stepcerts_enabled'] == 'true':
@@ -382,8 +384,12 @@
                     'cd /opt/ && sudo wget http://mirrors.sonic.net/apache/maven/maven-{0}/{1}/binaries/apache-maven-{1}-bin.zip '
                     '&& sudo unzip apache-maven-{1}-bin.zip && sudo mv apache-maven-{1} maven'.format(
                         maven_version.split('.')[0], maven_version))
-            datalab.fab.conn.sudo('bash -c "curl --silent --location https://deb.nodesource.com/setup_15.x | bash -"')
-            manage_pkg('-y install', 'remote', 'nodejs')
+            #datalab.fab.conn.sudo('bash -c "curl --silent --location https://deb.nodesource.com/setup_16.x | bash -"')
+            #manage_pkg('-y install', 'remote', 'nodejs')
+            datalab.fab.conn.sudo(
+                'curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash')
+            datalab.fab.conn.run('export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" && nvm install 16.15.0')
+            datalab.fab.conn.sudo('cp -R .nvm/versions/node/v16.15.0/* /usr/')
             datalab.fab.conn.sudo('npm config set unsafe-perm=true')
             datalab.fab.conn.sudo('touch {}tmp/build_dep_ensured'.format(os.environ['ssn_datalab_path']))
     except Exception as err:
diff --git a/infrastructure-provisioning/src/general/lib/os/fab.py b/infrastructure-provisioning/src/general/lib/os/fab.py
index 22215e6..62a464e 100644
--- a/infrastructure-provisioning/src/general/lib/os/fab.py
+++ b/infrastructure-provisioning/src/general/lib/os/fab.py
@@ -40,22 +40,27 @@
 
 
 # general functions for all resources
-def init_datalab_connection(hostname, username, keyfile):
+def init_datalab_connection(hostname, username, keyfile, reserve_user='', run_echo=True):
     try:
         global conn
-        attempt = 0
-        while attempt < 15:
-            logging.info('connection attempt {}'.format(attempt))
-            conn = Connection(host=hostname, user=username, connect_kwargs={'banner_timeout': 200,
+        if reserve_user:
+            users = [username, reserve_user]
+        else:
+            users = [username]
+        for user in users:
+            attempt = 0
+            while attempt < 15:
+                logging.info('connection attempt {} with user {}'.format(attempt, user))
+                conn = Connection(host=hostname, user=user, connect_kwargs={'banner_timeout': 200,
                                                                             'key_filename': keyfile})
-            conn.config.run.echo = True
-            try:
-                conn.run('hostname')
-                conn.config.run.echo = True
-                return conn
-            except:
-                attempt += 1
-                time.sleep(10)
+                conn.config.run.echo = run_echo
+                try:
+                    conn.run('hostname')
+                    conn.config.run.echo = run_echo
+                    return conn
+                except:
+                    attempt += 1
+                    time.sleep(10)
         if attempt == 15:
             logging.info('Unable to establish connection')
             raise Exception
@@ -311,6 +316,9 @@
 def ensure_python_venv_deeplearn(python_venv_version):
     try:
         if not exists(conn, '/opt/python/python{}'.format(python_venv_version)):
+            if os.environ['conf_cloud_provider'] == 'azure':
+                conn.sudo('rm /etc/apt/sources.list.d/cuda*')
+                conn.sudo('apt update')
             conn.sudo('add-apt-repository ppa:deadsnakes/ppa -y')
             conn.sudo('apt install python{0} -y'.format(python_venv_version[:3]))
             conn.sudo('apt install virtualenv')
@@ -363,6 +371,7 @@
             conn.sudo('''bash -l -c 'cd /tmp/Python-{0} && make altinstall' '''.format(python_venv_version))
             conn.sudo('''bash -l -c 'cd /tmp && rm -rf Python-{}' '''.format(python_venv_version))
             conn.sudo('''bash -l -c 'virtualenv /opt/python/python{0}' '''.format(python_venv_version))
+            conn.sudo('chown -R datalab-user:datalab-user /opt/python/')
             venv_command = 'source /opt/python/python{}/bin/activate'.format(python_venv_version)
             pip_command = '/opt/python/python{0}/bin/pip{1}'.format(python_venv_version, python_venv_version[:3])
             conn.sudo('''bash -l -c '{0} && {1} install -UI pip=={2}' '''.format(venv_command, pip_command,
@@ -379,6 +388,25 @@
         traceback.print_exc()
         sys.exit(1)
 
+def ensure_anaconda():
+    try:
+        if not exists(conn, '/opt/anaconda3'):
+            conn.sudo('wget https://repo.anaconda.com/archive/Anaconda3-2021.11-Linux-x86_64.sh -O /tmp/anaconda.sh')
+            conn.sudo('bash /tmp/anaconda.sh -b -p /opt/anaconda3')
+            conn.sudo('chown -R datalab-user /opt/anaconda3')
+            #conn.sudo(''' bash -l -c "echo 'export PATH=/opt/anaconda3/bin/:\$PATH' >> /home/datalab-user/.bashrc" ''')
+            #conn.run('source /home/datalab-user/.bashrc')
+            conn.run('source /opt/anaconda3/etc/profile.d/conda.sh && conda create -y -p /opt/anaconda3/envs/jupyter-conda git pip ipykernel -c anaconda')
+            conn.run('source /opt/anaconda3/etc/profile.d/conda.sh && conda activate jupyter-conda && /opt/anaconda3/envs/jupyter-conda/bin/pip install numpy scipy pandas scikit-learn transformers==4.4.2 gensim==4.0.1 tokenizers==0.10.1 python-levenshtein==0.12.2')
+            conn.run('source /opt/anaconda3/etc/profile.d/conda.sh && conda activate jupyter-conda && /opt/anaconda3/envs/jupyter-conda/bin/pip install -U torch==1.10.0+cu111 torchvision==0.11.3+cu111 torchaudio==0.10.2+cu111 -f https://download.pytorch.org/whl/cu111/torch_stable.html --no-cache-dir')
+            conn.sudo('chown -R datalab-user /home/datalab-user/.local/share/jupyter/kernels')
+            conn.run('source /opt/anaconda3/etc/profile.d/conda.sh && conda activate jupyter-conda && python -m ipykernel install --user --name=jupyter-conda')
+            conn.sudo('chown -R root /home/datalab-user/.local/share/jupyter/kernels')
+            conn.sudo('systemctl restart jupyter-notebook')
+    except Exception as err:
+        logging.error('Function ensure_anaconda error:', str(err))
+        traceback.print_exc()
+        sys.exit(1)
 
 def install_venv_pip_pkg(pkg_name, pkg_version=''):
     try:
@@ -509,13 +537,6 @@
          -O {}spark-tensorflow-connector-1.0.0-s_2.11.jar'.format(jars_dir), shell=True, check=True)
 
 
-def prepare(dataengine_service_dir, yarn_dir):
-    subprocess.run('mkdir -p ' + dataengine_service_dir, shell=True, check=True)
-    subprocess.run('mkdir -p ' + yarn_dir, shell=True, check=True)
-    subprocess.run('sudo mkdir -p /opt/python/', shell=True, check=True)
-    result = os.path.exists(dataengine_service_dir + 'usr/')
-    return result
-
 def install_r_pkg(requisites):
     status = list()
     error_parser = "ERROR:|error:|Cannot|failed|Please run|requires|Error|Skipping|couldn't find"
@@ -689,7 +710,10 @@
     if not exists(conn, '/home/{}/.ensure_dir/ungit_ensured'.format(os_user)):
         try:
             manage_npm_pkg('npm -g install ungit@{}'.format(os.environ['notebook_ungit_version']))
-            conn.put('/root/templates/ungit.service', '/tmp/ungit.service')
+            if os.environ['conf_deeplearning_cloud_ami'] =='true' and os.environ['conf_cloud_provider'] =='azure' and os.environ['application'] =='deeplearning':
+                conn.put('/root/templates/ungit.service.18_04', '/tmp/ungit.service')
+            else:
+                conn.put('/root/templates/ungit.service', '/tmp/ungit.service')
             conn.sudo("sed -i 's|OS_USR|{}|' /tmp/ungit.service".format(os_user))
             http_proxy = conn.run('''bash -l -c 'echo $http_proxy' ''').stdout.replace('\n', '')
             conn.sudo("sed -i 's|PROXY_HOST|{}|g' /tmp/ungit.service".format(http_proxy))
@@ -974,12 +998,12 @@
         try:
             if os.environ['conf_deeplearning_cloud_ami'] == 'false' or os.environ['application'] != 'deeplearning':
                 conn.sudo('pip3 install notebook=={} --no-cache-dir'.format(jupyter_version))
-                conn.sudo('pip3 install jupyter --no-cache-dir')
+                conn.sudo('pip3 install jupyter MarkupSafe==2.0.1 --no-cache-dir') # requires investigation
                 conn.sudo('rm -rf {}'.format(jupyter_conf_file))
             elif os.environ['application'] != 'tensor':
-                conn.sudo('pip3 install environment_kernels')
-            if os.environ['conf_cloud_provider'] == 'aws' and os.environ['application'] == 'deeplearning': #should be checked if for other applications any files have owner root:root in datalab-user homefolder and where it is changed to root:root on deeplearning
-                conn.sudo('chown -R {0}:{0} /home/{0}/.local'.format(os_user))
+                conn.sudo('-i pip3 install environment_kernels')
+            #if os.environ['conf_cloud_provider'] == 'aws' and os.environ['application'] == 'deeplearning': #should be checked if for other applications any files have owner root:root in datalab-user homefolder and where it is changed to root:root on deeplearning
+            #    conn.sudo( pip3 install flask'chown -R {0}:{0} /home/{0}/.local'.format(os_user))
             conn.run('jupyter notebook --generate-config --config {}'.format(jupyter_conf_file))
             conn.run('mkdir -p ~/.jupyter/custom/')
             conn.run('echo "#notebook-container { width: auto; }" > ~/.jupyter/custom/custom.css')
@@ -1043,6 +1067,47 @@
             sys.exit(1)
 
 
+# jupyterlab
+def configure_jupyterlab(os_user, jupyterlab_conf_file, templates_dir, jupyterlab_version, exploratory_name):
+    if not exists(conn, '/home/' + os_user + '/.ensure_dir/jupyterlab_ensured'):
+        try:
+            conn.sudo('pip3 install jupyterlab --no-cache-dir')  # create external var with version
+            conn.sudo('rm -rf {}'.format(jupyterlab_conf_file))
+            conn.run('jupyter lab --generate-config')
+            conn.sudo('echo "c.NotebookApp.ip = \'0.0.0.0\'" >> {}'.format(jupyterlab_conf_file))
+            conn.sudo('echo "c.NotebookApp.base_url = \'/{0}/\'" >> {1}'.format(exploratory_name, jupyterlab_conf_file))
+            conn.sudo('echo c.NotebookApp.open_browser = False >> {}'.format(jupyterlab_conf_file))
+            conn.sudo('echo \'c.NotebookApp.cookie_secret = b"{0}"\' >> {1}'.format(id_generator(), jupyterlab_conf_file))
+            conn.sudo('''echo "c.NotebookApp.token = u''" >> {}'''.format(jupyterlab_conf_file))
+            conn.sudo('echo \'c.KernelSpecManager.ensure_native_kernel = False\' >> {}'.format(jupyterlab_conf_file))
+            conn.put(templates_dir + 'jupyterlab-notebook.service', '/tmp/jupyterlab-notebook.service')
+            if os.environ['application'] == 'deeplearning' and os.environ['conf_cloud_provider'] == 'azure':
+                java_home = conn.run("update-alternatives --query java | grep -o --color=never \'/.*/java-11.*/bin/java\'").stdout.splitlines()[0]
+            else:
+                java_home = conn.run("update-alternatives --query java | grep -o --color=never \'/.*/java-8.*/jre\'").stdout.splitlines()[0]
+            # conn.sudo('sed -i \'/\[Service\]/ a\Environment=\"JAVA_HOME={}\"\'  /tmp/jupyterlab-notebook.service'.format(
+            #    java_home))
+            conn.sudo('cp /tmp/jupyterlab-notebook.service /etc/systemd/system/jupyterlab-notebook.service')
+            conn.sudo("systemctl daemon-reload")
+            conn.sudo("systemctl enable jupyterlab-notebook")
+            conn.sudo("systemctl start jupyterlab-notebook")
+            conn.sudo('touch /home/{}/.ensure_dir/jupyterlab_ensured'.format(os_user))
+        except Exception as err:
+            logging.error('Function configure_jupyterlab error:', str(err))
+            traceback.print_exc()
+            sys.exit(1)
+    else:
+        try:
+            conn.sudo(
+                'sed -i "s/c.NotebookApp.base_url =.*/c.NotebookApp.base_url = \'\/{0}\/\'/" {1}'.format(
+                    exploratory_name, jupyterlab_conf_file))
+            conn.sudo("systemctl restart jupyterlab-notebook")
+        except Exception as err:
+            logging.error('Function configure_jupyterlab error:', str(err))
+            traceback.print_exc()
+            sys.exit(1)
+
+
 def ensure_py3spark_local_kernel(os_user, py3spark_local_path_dir, templates_dir, spark_version, python_venv_path,
                                  python_venv_version):
     if not exists(conn, '/home/' + os_user + '/.ensure_dir/py3spark_local_kernel_ensured'):
@@ -1119,6 +1184,7 @@
     if not exists(conn, '/home/{}/.ensure_dir/unexisting_kernel_removed'.format(os_user)):
         try:
             conn.sudo('jupyter-kernelspec remove -f python3')
+            conn.sudo('jupyter kernelspec uninstall -y python3', warn=True)
             conn.sudo('touch /home/{}/.ensure_dir/unexisting_kernel_removed'.format(os_user))
         except Exception as err:
             logging.error('Function remove_unexisting_kernel error:', str(err))
@@ -1253,18 +1319,17 @@
                        keycloak_client_secret, edge_instance_private_ip, edge_instance_public_ip, superset_name):
     logging.info('Superset configuring')
     try:
-        if not exists(conn, '/home/{}/incubator-superset'.format(os_user)):
+        if not exists(conn, '/home/{}/superset'.format(os_user)):
             conn.sudo(
                 '''bash -c 'cd /home/{} && wget https://github.com/apache/incubator-superset/archive/{}.tar.gz' '''.format(
                     os_user, os.environ['notebook_superset_version']))
             conn.sudo('''bash -c 'cd /home/{} && tar -xzf {}.tar.gz' '''.format(os_user, os.environ[
                 'notebook_superset_version']))
-            conn.sudo('''bash -c 'cd /home/{} && ln -sf incubator-superset-{} incubator-superset' '''.format(os_user,
-                                                                                                             os.environ[
-                                                                                                                 'notebook_superset_version']))
+            conn.sudo('''bash -c 'cd /home/{} && ln -sf superset-{} superset' '''.format(os_user,
+                                                                                         os.environ['notebook_superset_version']))
         if not exists(conn, '/tmp/superset-notebook_installed'):
             conn.sudo('mkdir -p /opt/datalab/templates')
-            conn.local('cd  /root/templates; tar -zcvf /tmp/templates.tar.gz *')
+            conn.local('cd  /root/templates; tar -zcvf /tmp/templates.tar.gz .')
             conn.put('/tmp/templates.tar.gz', '/tmp/templates.tar.gz')
             conn.sudo('tar -zxvf /tmp/templates.tar.gz -C /opt/datalab/templates')
             conn.sudo('sed -i \'s/OS_USER/{}/g\' /opt/datalab/templates/.env'.format(os_user))
@@ -1281,23 +1346,27 @@
                 keycloak_auth_server_url))
             conn.sudo('sed -i \'s/KEYCLOAK_REALM_NAME/{}/g\' /opt/datalab/templates/superset_config.py'.format(
                 keycloak_realm_name))
+            conn.sudo('sed -i \'s/OS_USER/{}/g\' /opt/datalab/templates/superset_config.py'.format(os_user))
             conn.sudo(
                 'sed -i \'s/EDGE_IP/{}/g\' /opt/datalab/templates/superset_config.py'.format(edge_instance_public_ip))
             conn.sudo('sed -i \'s/SUPERSET_NAME/{}/g\' /opt/datalab/templates/superset_config.py'.format(superset_name))
-            conn.sudo('cp -f /opt/datalab/templates/.env /home/{}/incubator-superset/contrib/docker/'.format(os_user))
+            conn.sudo('cp -f /opt/datalab/templates/.env /home/{}/superset/docker/'.format(os_user))
             conn.sudo(
-                'cp -f /opt/datalab/templates/docker-compose.yml /home/{}/incubator-superset/contrib/docker/'.format(
+                'cp -f /opt/datalab/templates/docker-compose.yml /home/{}/superset/'.format(
                     os_user))
             conn.sudo(
-                'cp -f /opt/datalab/templates/id_provider.json /home/{}/incubator-superset/contrib/docker/'.format(
+                'cp -f /opt/datalab/templates/id_provider.json /home/{}/superset/docker/'.format(
                     os_user))
             conn.sudo(
-                'cp -f /opt/datalab/templates/requirements-extra.txt /home/{}/incubator-superset/contrib/docker/'.format(
+                'cp -f /opt/datalab/templates/requirements-extra.txt /home/{}/superset/requirements/'.format(
                     os_user))
             conn.sudo(
-                'cp -f /opt/datalab/templates/superset_config.py /home/{}/incubator-superset/contrib/docker/'.format(
+                'cp -f /opt/datalab/templates/superset_config.py /home/{}/superset/docker/pythonpath_dev/'.format(
                     os_user))
-            conn.sudo('cp -f /opt/datalab/templates/docker-init.sh /home/{}/incubator-superset/contrib/docker/'.format(
+            conn.sudo(
+                'cp -f /opt/datalab/templates/keycloak_security_manager.py /home/{}/superset/docker/pythonpath_dev/'.format(
+                    os_user))
+            conn.sudo('cp -f /opt/datalab/templates/docker-init.sh /home/{}/superset/docker/'.format(
                 os_user))
             conn.sudo('touch /tmp/superset-notebook_installed')
     except Exception as err:
@@ -1359,3 +1428,9 @@
             conn.sudo('touch /home/{}/.ensure_dir/pyopenssl_updated'.format(os_user))
         except:
             sys.exit(1)
+
+def get_hdinsight_headnode_private_ip(os_user, cluster_name, keyfile):
+    init_datalab_connection('{}-ssh.azurehdinsight.net'.format(cluster_name), os_user, keyfile)
+    headnode_private_ip = conn.sudo("cat /etc/hosts | grep headnode | awk '{print $1}'").stdout
+    conn.close()
+    return headnode_private_ip
diff --git a/infrastructure-provisioning/src/general/lib/os/redhat/ssn_lib.py b/infrastructure-provisioning/src/general/lib/os/redhat/ssn_lib.py
index 39ad178..4ebed0f 100644
--- a/infrastructure-provisioning/src/general/lib/os/redhat/ssn_lib.py
+++ b/infrastructure-provisioning/src/general/lib/os/redhat/ssn_lib.py
@@ -289,7 +289,7 @@
                 sys.exit(1)
 
             if billing_enabled:
-                conn.local('scp -i {} /root/scripts/configure_billing.py {}:/tmp/configure_billing.py'.format(keyfile,
+                conn.local('rsync -e "ssh -i {}" /root/scripts/configure_billing.py {}:/tmp/configure_billing.py'.format(keyfile,
                                                                                                          host_string))
                 params = '--cloud_provider {} ' \
                          '--infrastructure_tag {} ' \
diff --git a/infrastructure-provisioning/src/general/scripts/aws/common_collect_data.py b/infrastructure-provisioning/src/general/scripts/aws/common_collect_data.py
index a81e373..6cbb2fc 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/common_collect_data.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/common_collect_data.py
@@ -50,6 +50,11 @@
             statuses['cluster'] = data_clusters
         except:
             logging.info("Clusters JSON wasn't provided")
+        try:
+            data_images = get_list_image_statuses(data.get('image'))
+            statuses['image'] = data_images
+        except:
+            logging.info("Images JSON wasn't been provided")
         with open('/root/result.json', 'w') as outfile:
             json.dump(statuses, outfile)
     except Exception as err:
diff --git a/infrastructure-provisioning/src/general/scripts/aws/common_create_bucket.py b/infrastructure-provisioning/src/general/scripts/aws/common_create_bucket.py
index b34a83a..16f5cd0 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/common_create_bucket.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/common_create_bucket.py
@@ -32,6 +32,7 @@
 parser.add_argument('--bucket_tags', type=str, default='')
 parser.add_argument('--region', type=str, default='')
 parser.add_argument('--bucket_name_tag', type=str, default='')
+parser.add_argument('--bucket_versioning_enabled', type=str, default='')
 args = parser.parse_args()
 
 if __name__ == "__main__":
@@ -40,7 +41,8 @@
             bucket = get_bucket_by_name(args.bucket_name)
             if bucket == '':
                 logging.info("Creating bucket {0} with tags {1}.".format(args.bucket_name, args.bucket_tags))
-                bucket = create_s3_bucket(args.bucket_name, args.bucket_tags, args.region, args.bucket_name_tag)
+                bucket = create_s3_bucket(args.bucket_name, args.bucket_tags, args.region, args.bucket_name_tag,
+                                          args.bucket_versioning_enabled)
             else:
                 logging.info("REQUESTED BUCKET ALREADY EXISTS")
             logging.info("BUCKET_NAME {}".format(bucket))
diff --git a/infrastructure-provisioning/src/general/scripts/aws/common_create_notebook_image.py b/infrastructure-provisioning/src/general/scripts/aws/common_create_notebook_image.py
index 3c08b5e..8cf7b51 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/common_create_notebook_image.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/common_create_notebook_image.py
@@ -67,6 +67,11 @@
                                                                       instance_name=image_conf['instance_name'],
                                                                       image_name=image_conf['full_image_name'],
                                                                       tags=json.dumps(image_conf['tags']))
+
+            logging.info("Image id from actions.lib.py {}".format(image_id))
+            if not image_id :
+                raise Exception("Image can not be created from not running instances")
+
             logging.info("Image was successfully created. It's name is {}".format(image_conf['full_image_name']))
 
             with open("/root/result.json", 'w') as result:
@@ -74,9 +79,9 @@
                        "full_image_name": image_conf['full_image_name'],
                        "project_name": image_conf['project_name'],
                        "application": image_conf['application'],
-                       "status": "created",
+                       "status": "active",
                        "Action": "Create image from notebook"}
                 result.write(json.dumps(res))
     except Exception as err:
         datalab.fab.append_result("Failed to create image from notebook", str(err))
-        sys.exit(1)
+        sys.exit(1)
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/general/scripts/aws/common_notebook_configure_dataengine.py b/infrastructure-provisioning/src/general/scripts/aws/common_notebook_configure_dataengine.py
index f9e133c..4b74810 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/common_notebook_configure_dataengine.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/common_notebook_configure_dataengine.py
@@ -54,11 +54,11 @@
         logging.info('Generating infrastructure names and tags')
         notebook_config = dict()
         if 'exploratory_name' in os.environ:
-            notebook_config['exploratory_name'] = os.environ['exploratory_name']
+            notebook_config['exploratory_name'] = os.environ['exploratory_name'].lower()
         else:
             notebook_config['exploratory_name'] = ''
         if 'computational_name' in os.environ:
-            notebook_config['computational_name'] = os.environ['computational_name']
+            notebook_config['computational_name'] = os.environ['computational_name'].lower()
         else:
             notebook_config['computational_name'] = ''
         notebook_config['service_base_name'] = os.environ['conf_service_base_name'] = datalab.fab.replace_multi_symbols(
diff --git a/infrastructure-provisioning/src/general/scripts/aws/common_prepare_notebook.py b/infrastructure-provisioning/src/general/scripts/aws/common_prepare_notebook.py
index 6d40ffe..c45f424 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/common_prepare_notebook.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/common_prepare_notebook.py
@@ -69,18 +69,24 @@
             sys.exit(1)
         logging.info('Generating infrastructure names and tags')
         try:
-            notebook_config['exploratory_name'] = os.environ['exploratory_name']
+            notebook_config['exploratory_name'] = os.environ['exploratory_name'].lower()
         except:
             notebook_config['exploratory_name'] = ''
-
+        notebook_config['custom_tag'] = ''
+        if 'custom_tag' in os.environ['tags']:
+            notebook_config['custom_tag'] = json.loads(os.environ['tags'].replace("'", '"'))['custom_tag']
+            if notebook_config['custom_tag']:
+                notebook_config['custom_tag'] = ';custom_tag:{}'.format(notebook_config['custom_tag'])
         notebook_config['instance_type'] = os.environ['aws_notebook_instance_type']
         notebook_config['key_name'] = os.environ['conf_key_name']
         notebook_config['instance_name'] = '{}-{}-{}-nb-{}-{}'.format(notebook_config['service_base_name'],
                                                                       notebook_config['project_name'],
                                                                       notebook_config['endpoint_name'],
                                                                       notebook_config['exploratory_name'], args.uuid)
-        notebook_config['primary_disk_size'] = (lambda x: '100' if x == 'deeplearning' else '16')(
-            os.environ['application'])
+
+        notebook_config['primary_disk_size'] = (lambda x: '150' if x == 'deeplearning' else
+        ('28' if x == 'tensor' or x == 'tensor-rstudio' else '16'))(os.environ['application'])
+
         notebook_config['role_profile_name'] = '{}-{}-{}-nb-de-profile'.format(
             notebook_config['service_base_name'], notebook_config['project_name'], notebook_config['endpoint_name'])
         notebook_config['security_group_name'] = '{}-{}-{}-nb-sg'.format(notebook_config['service_base_name'],
@@ -109,6 +115,11 @@
             notebook_config['ami_id'] = image_id
             logging.info('Pre-configured image found. Using: {}'.format(notebook_config['ami_id']))
         else:
+            if 'notebook_image_name' in os.environ:
+                logging.info('{} is available in the list for notebook creation but image_id '
+                             'is not present on the cloud'.format(os.environ['notebook_image_name']))
+                sys.exit(1)
+
             os.environ['notebook_image_name'] = os.environ['aws_{}_image_name'.format(os.environ['conf_os_family'])]
             logging.info('No pre-configured image found. Using default one: {}'.format(notebook_config['ami_id']))
 
@@ -123,11 +134,12 @@
             json.dump(data, f)
 
         try:
-            os.environ['conf_additional_tags'] = '{2};project_tag:{0};endpoint_tag:{1};'.format(
-                notebook_config['project_name'], notebook_config['endpoint_name'], os.environ['conf_additional_tags'])
-        except KeyError:
-            os.environ['conf_additional_tags'] = 'project_tag:{0};endpoint_tag:{1}'.format(
-                notebook_config['project_name'], notebook_config['endpoint_name'])
+            os.environ['conf_additional_tags'] = '{2};project_tag:{0};endpoint_tag:{1}{3}'.format(
+                notebook_config['project_name'], notebook_config['endpoint_name'], os.environ['conf_additional_tags'],
+                notebook_config['custom_tag'])
+        except KeyError as ex:
+            os.environ['conf_additional_tags'] = 'project_tag:{0};endpoint_tag:{1}{2}'.format(
+                notebook_config['project_name'], notebook_config['endpoint_name'], notebook_config['custom_tag'])
 
         logging.info('Additional tags will be added: {}'.format(os.environ['conf_additional_tags']))
     except Exception as err:
diff --git a/infrastructure-provisioning/src/general/scripts/aws/common_terminate_notebook.py b/infrastructure-provisioning/src/general/scripts/aws/common_terminate_notebook.py
index a7e92f1..2220a79 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/common_terminate_notebook.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/common_terminate_notebook.py
@@ -65,6 +65,44 @@
     except:
         sys.exit(1)
 
+    if os.environ['notebook_create_keycloak_client'] == 'True':
+        logging.info("Terminating notebook keycloak client")
+        try:
+            keycloak_auth_server_url = '{}/realms/master/protocol/openid-connect/token'.format(
+                os.environ['keycloak_auth_server_url'])
+            keycloak_client_url = '{0}/admin/realms/{1}/clients'.format(os.environ['keycloak_auth_server_url'],
+                                                                        os.environ['keycloak_realm_name'])
+
+            keycloak_auth_data = {
+                "username": os.environ['keycloak_user'],
+                "password": os.environ['keycloak_user_password'],
+                "grant_type": "password",
+                "client_id": "admin-cli",
+            }
+
+            client_params = {
+                "clientId": "{}-{}-{}-{}".format(notebook_config['service_base_name'], notebook_config['project_name'],
+                                                 notebook_config['endpoint_name'], notebook_config['exploratory_name'])
+            }
+
+            keycloak_token = requests.post(keycloak_auth_server_url, data=keycloak_auth_data).json()
+
+            keycloak_get_id_client = requests.get(keycloak_client_url, data=keycloak_auth_data, params=client_params,
+                                                  headers={"Authorization": "Bearer " + keycloak_token.get("access_token"),
+                                                           "Content-Type": "application/json"})
+            json_keycloak_client_id = json.loads(keycloak_get_id_client.text)
+            keycloak_id_client = json_keycloak_client_id[0]['id']
+
+            keycloak_client_delete_url = '{0}/admin/realms/{1}/clients/{2}'.format(os.environ['keycloak_auth_server_url'],
+                                                                                   os.environ['keycloak_realm_name'],
+                                                                                   keycloak_id_client)
+
+            requests.delete(keycloak_client_delete_url,
+                            headers={"Authorization": "Bearer " + keycloak_token.get("access_token"),
+                                     "Content-Type": "application/json"})
+        except Exception as err:
+            logging.error("Failed to remove project client from Keycloak", str(err))
+
 
 if __name__ == "__main__":
     # generating variables dictionary
@@ -79,6 +117,12 @@
                                                                   notebook_config['project_name'],
                                                                   notebook_config['endpoint_name']
                                                                  ).lower().replace('_', '-')
+
+    try:
+        notebook_config['exploratory_name'] = os.environ['exploratory_name'].lower()
+    except:
+        notebook_config['exploratory_name'] = ''
+
     notebook_config['tag_name'] = notebook_config['service_base_name'] + '-tag'
 
     try:
diff --git a/infrastructure-provisioning/src/general/scripts/aws/common_terminate_notebook_image.py b/infrastructure-provisioning/src/general/scripts/aws/common_terminate_notebook_image.py
index e076c51..140f15a 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/common_terminate_notebook_image.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/common_terminate_notebook_image.py
@@ -32,17 +32,29 @@
     try:
         datalab.actions_lib.create_aws_config_files()
         image_conf = dict()
-        image_conf['full_image_name'] = os.environ['notebook_image_name']
-
+        image_conf['service_base_name'] = os.environ['conf_service_base_name'] = datalab.fab.replace_multi_symbols(
+            os.environ['conf_service_base_name'][:20], '-', True)
+        image_conf['project_name'] = os.environ['project_name']
+        image_conf['endpoint_name'] = os.environ['endpoint_name']
+        image_conf['application'] = os.environ['application']
+        image_conf['image_name'] = os.environ['notebook_image_name']
+        image_conf['full_image_name'] = '{}-{}-{}-{}-{}'.format(image_conf['service_base_name'],
+                                                                image_conf['project_name'],
+                                                                image_conf['endpoint_name'],
+                                                                image_conf['application'],
+                                                                image_conf['image_name'])
         image_id = datalab.meta_lib.get_ami_id_by_name(image_conf['full_image_name'], 'available')
         if image_id != '':
             datalab.actions_lib.deregister_image(image_conf['full_image_name'])
 
-            with open("/root/result.json", 'w') as result:
-                res = {"notebook_image_name": image_conf['full_image_name'],
-                       "status": "terminated",
-                       "Action": "Delete existing notebook image"}
-                result.write(json.dumps(res))
+        with open("/root/result.json", 'w') as result:
+            res = {"notebook_image_name": image_conf['full_image_name'],
+                   "endpoint": image_conf['endpoint_name'],
+                   "project": image_conf['project_name'],
+                   "imageName": image_conf['image_name'],
+                   "status": "terminated",
+                   "Action": "Delete existing notebook image"}
+            result.write(json.dumps(res))
     except Exception as err:
         datalab.fab.append_result("Failed to delete existing notebook image", str(err))
         sys.exit(1)
diff --git a/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_configure.py b/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_configure.py
index 0aebdf5..03a906b 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_configure.py
@@ -37,6 +37,7 @@
 
 parser = argparse.ArgumentParser()
 parser.add_argument('--uuid', type=str, default='')
+parser.add_argument('--access_password', type=str, default='')
 args = parser.parse_args()
 
 
@@ -162,11 +163,11 @@
         logging.info('Generating infrastructure names and tags')
         emr_conf = dict()
         if 'exploratory_name' in os.environ:
-            emr_conf['exploratory_name'] = os.environ['exploratory_name']
+            emr_conf['exploratory_name'] = os.environ['exploratory_name'].lower()
         else:
             emr_conf['exploratory_name'] = ''
         if 'computational_name' in os.environ:
-            emr_conf['computational_name'] = os.environ['computational_name']
+            emr_conf['computational_name'] = os.environ['computational_name'].lower()
         else:
             emr_conf['computational_name'] = ''
         emr_conf['apps'] = 'Hadoop Hive Hue Spark Livy'
diff --git a/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_prepare.py b/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_prepare.py
index c5a2d0d..64f5518 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_prepare.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_prepare.py
@@ -36,6 +36,7 @@
 
 parser = argparse.ArgumentParser()
 parser.add_argument('--uuid', type=str, default='')
+parser.add_argument('--access_password', type=str, default='')
 args = parser.parse_args()
 
 if __name__ == "__main__":
@@ -48,7 +49,7 @@
     try:
         emr_conf = dict()
         if 'exploratory_name' in os.environ:
-            emr_conf['exploratory_name'] = os.environ['exploratory_name']
+            emr_conf['exploratory_name'] = os.environ['exploratory_name'].lower()
         else:
             emr_conf['exploratory_name'] = ''
         if os.path.exists('/response/.emr_creating_{}'.format(emr_conf['exploratory_name'])):
@@ -73,7 +74,7 @@
             sys.exit(1)
         logging.info('Generating infrastructure names and tags')
         if 'computational_name' in os.environ:
-            emr_conf['computational_name'] = os.environ['computational_name']
+            emr_conf['computational_name'] = os.environ['computational_name'].lower()
         else:
             emr_conf['computational_name'] = ''
         emr_conf['apps'] = 'Hadoop Hive Hue Spark Livy'
@@ -87,7 +88,8 @@
                                                                    emr_conf['project_name'], emr_conf['endpoint_name'])
         emr_conf['edge_security_group_name'] = '{0}-sg'.format(emr_conf['edge_instance_name'])
         emr_conf['nb_security_group_name'] = '{0}-{1}-{2}-nb-sg'.format(emr_conf['service_base_name'],
-                                                                   emr_conf['project_name'], emr_conf['endpoint_name'])
+                                                                        emr_conf['project_name'],
+                                                                        emr_conf['endpoint_name'])
         emr_conf['master_instance_type'] = os.environ['emr_master_instance_type']
         emr_conf['slave_instance_type'] = os.environ['emr_slave_instance_type']
         emr_conf['instance_count'] = os.environ['emr_instance_count']
@@ -99,22 +101,30 @@
                            '{0}-tag={0}-{1}-{5}-des-{3},' \
                            'Notebook={4},' \
                            'State=not-configured,' \
-                           'ComputationalName={3},' \
-                           'Endpoint_tag={5}'\
+                           'ComputationalName={3}' \
             .format(emr_conf['service_base_name'],
                     emr_conf['project_name'],
                     emr_conf['exploratory_name'],
                     emr_conf['computational_name'],
                     os.environ['notebook_instance_name'],
                     emr_conf['endpoint_name'])
-        emr_conf['cluster_name'] = '{0}-{1}-{2}-des-{3}-{4}'\
+        additional_tags = os.environ['tags'].replace("': '", ":").replace("', '", ",").replace("{'", "").replace(
+            "'}", "").lower()
+        for tag in additional_tags.split(','):
+            label_key = tag.split(':')[0]
+            label_value = tag.split(':')[1].replace('_', '-')
+            if '@' in label_value:
+                label_value = label_value[:label_value.find('@')]
+            if label_value != '':
+                emr_conf['tags'] = '{}={},{}'.format(label_key, label_value, emr_conf['tags'])
+        emr_conf['cluster_name'] = '{0}-{1}-{2}-des-{3}-{4}' \
             .format(emr_conf['service_base_name'],
                     emr_conf['project_name'],
                     emr_conf['endpoint_name'],
                     emr_conf['computational_name'],
                     args.uuid)
         emr_conf['bucket_name'] = '{0}-{1}-{2}-bucket'.format(emr_conf['service_base_name'], emr_conf['project_name'],
-                                                               emr_conf['endpoint_name']).lower().replace('_', '-')
+                                                              emr_conf['endpoint_name']).lower().replace('_', '-')
         emr_conf['configurations'] = '[]'
         if 'emr_configurations' in os.environ:
             emr_conf['configurations'] = os.environ['emr_configurations']
@@ -125,7 +135,7 @@
         emr_conf['subnet_cidr'] = datalab.meta_lib.get_subnet_by_tag(tag)
         emr_conf['key_path'] = '{0}{1}.pem'.format(os.environ['conf_key_dir'], os.environ['conf_key_name'])
         emr_conf['all_ip_cidr'] = '0.0.0.0/0'
-        emr_conf['additional_emr_sg_name'] = '{}-{}-{}-de-se-additional-sg'\
+        emr_conf['additional_emr_sg_name'] = '{}-{}-{}-de-se-additional-sg' \
             .format(emr_conf['service_base_name'], emr_conf['project_name'], emr_conf['endpoint_name'])
         emr_conf['vpc_id'] = os.environ['aws_vpc_id']
         emr_conf['vpc2_id'] = os.environ['aws_notebook_vpc_id']
@@ -240,8 +250,9 @@
                    emr_conf['cluster_name'], True)
         try:
             if 'conf_additional_tags' in os.environ:
-                os.environ['conf_additional_tags'] = '{2};project_tag:{0};endpoint_tag:{1};'.format(
-                    emr_conf['project_tag'], emr_conf['endpoint_tag'], os.environ['conf_additional_tags'])
+                os.environ['conf_additional_tags'] = '{2};project_tag:{0};endpoint_tag:{1}'.format(
+                    emr_conf['project_tag'], emr_conf['endpoint_tag'],
+                    os.environ['conf_additional_tags'])
             else:
                 os.environ['conf_additional_tags'] = 'project_tag:{0};endpoint_tag:{1}'.format(emr_conf['project_tag'],
                                                                                                emr_conf['endpoint_tag'])
@@ -280,7 +291,7 @@
                  "--bid_price {19} " \
                  "--service_base_name {20} " \
                  "--additional_emr_sg {21} " \
-                 "--configurations \"{22}\" "\
+                 "--configurations \"{22}\" " \
             .format(emr_conf['cluster_name'],
                     emr_conf['apps'],
                     emr_conf['master_instance_type'],
diff --git a/infrastructure-provisioning/src/general/scripts/aws/dataengine_configure.py b/infrastructure-provisioning/src/general/scripts/aws/dataengine_configure.py
index e9bbf11..def8065 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/dataengine_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/dataengine_configure.py
@@ -143,11 +143,11 @@
         logging.info('Generating infrastructure names and tags')
         data_engine = dict()
         if 'exploratory_name' in os.environ:
-            data_engine['exploratory_name'] = os.environ['exploratory_name']
+            data_engine['exploratory_name'] = os.environ['exploratory_name'].lower()
         else:
             data_engine['exploratory_name'] = ''
         if 'computational_name' in os.environ:
-            data_engine['computational_name'] = os.environ['computational_name']
+            data_engine['computational_name'] = os.environ['computational_name'].lower()
         else:
             data_engine['computational_name'] = ''
         data_engine['service_base_name'] = (os.environ['conf_service_base_name'])
diff --git a/infrastructure-provisioning/src/general/scripts/aws/dataengine_prepare.py b/infrastructure-provisioning/src/general/scripts/aws/dataengine_prepare.py
index 4593fc5..1fae3ef 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/dataengine_prepare.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/dataengine_prepare.py
@@ -59,13 +59,18 @@
             sys.exit(1)
         logging.info('Generating infrastructure names and tags')
         if 'exploratory_name' in os.environ:
-            data_engine['exploratory_name'] = os.environ['exploratory_name']
+            data_engine['exploratory_name'] = os.environ['exploratory_name'].lower()
         else:
             data_engine['exploratory_name'] = ''
         if 'computational_name' in os.environ:
-            data_engine['computational_name'] = os.environ['computational_name']
+            data_engine['computational_name'] = os.environ['computational_name'].lower()
         else:
             data_engine['computational_name'] = ''
+        data_engine['custom_tag'] = ''
+        if 'custom_tag' in os.environ['tags']:
+            data_engine['custom_tag'] = json.loads(os.environ['tags'].replace("'", '"'))['custom_tag']
+        if data_engine['custom_tag']:
+            data_engine['custom_tag'] = ';custom_tag:{}'.format(data_engine['custom_tag'])
         data_engine['tag_name'] = data_engine['service_base_name'] + '-tag'
         data_engine['key_name'] = os.environ['conf_key_name']
         data_engine['region'] = os.environ['aws_region']
@@ -138,11 +143,13 @@
         json.dump(data, f)
 
     try:
-        os.environ['conf_additional_tags'] = '{2};project_tag:{0};endpoint_tag:{1};'.format(
-            data_engine['project_name'], data_engine['endpoint_name'], os.environ['conf_additional_tags'])
+        os.environ['conf_additional_tags'] = '{2};project_tag:{0};endpoint_tag:{1}{3}'.format(
+            data_engine['project_name'], data_engine['endpoint_name'], os.environ['conf_additional_tags'],
+            data_engine['custom_tag'])
     except KeyError:
-        os.environ['conf_additional_tags'] = 'project_tag:{0};endpoint_tag:{1}'.format(data_engine['project_name'],
-                                                                                       data_engine['endpoint_name'])
+        os.environ['conf_additional_tags'] = 'project_tag:{0};endpoint_tag:{1}{2}'.format(
+            data_engine['project_name'], data_engine['endpoint_name'], data_engine['custom_tag'])
+
     logging.info('Additional tags will be added: {}'.format(os.environ['conf_additional_tags']))
 
     try:
diff --git a/infrastructure-provisioning/src/general/scripts/aws/dataengine_start.py b/infrastructure-provisioning/src/general/scripts/aws/dataengine_start.py
index 073ad77..e3c8cb7 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/dataengine_start.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/dataengine_start.py
@@ -57,11 +57,11 @@
     data_engine = dict()
     
     try:
-        data_engine['exploratory_name'] = os.environ['exploratory_name']
+        data_engine['exploratory_name'] = os.environ['exploratory_name'].lower()
     except:
         data_engine['exploratory_name'] = ''
     try:
-        data_engine['computational_name'] = os.environ['computational_name']
+        data_engine['computational_name'] = os.environ['computational_name'].lower()
     except:
         data_engine['computational_name'] = ''
     data_engine['service_base_name'] = (os.environ['conf_service_base_name'])
diff --git a/infrastructure-provisioning/src/general/scripts/aws/dataengine_stop.py b/infrastructure-provisioning/src/general/scripts/aws/dataengine_stop.py
index 26f7e81..b662a4c 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/dataengine_stop.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/dataengine_stop.py
@@ -43,11 +43,11 @@
     logging.info('Generating infrastructure names and tags')
     data_engine_config = dict()
     try:
-        data_engine_config['exploratory_name'] = os.environ['exploratory_name']
+        data_engine_config['exploratory_name'] = os.environ['exploratory_name'].lower()
     except:
         data_engine_config['exploratory_name'] = ''
     try:
-        data_engine_config['computational_name'] = os.environ['computational_name']
+        data_engine_config['computational_name'] = os.environ['computational_name'].lower()
     except:
         data_engine_config['computational_name'] = ''
     data_engine_config['service_base_name'] = (os.environ['conf_service_base_name'])
diff --git a/infrastructure-provisioning/src/general/scripts/aws/dataengine_terminate.py b/infrastructure-provisioning/src/general/scripts/aws/dataengine_terminate.py
index 4ecb377..8d9c23c 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/dataengine_terminate.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/dataengine_terminate.py
@@ -62,11 +62,11 @@
     data_engine = dict()
     
     try:
-        data_engine['exploratory_name'] = os.environ['exploratory_name']
+        data_engine['exploratory_name'] = os.environ['exploratory_name'].lower()
     except:
         data_engine['exploratory_name'] = ''
     try:
-        data_engine['computational_name'] = os.environ['computational_name']
+        data_engine['computational_name'] = os.environ['computational_name'].lower()
     except:
         data_engine['computational_name'] = ''
     data_engine['service_base_name'] = (os.environ['conf_service_base_name'])
diff --git a/infrastructure-provisioning/src/general/scripts/aws/edge_configure.py b/infrastructure-provisioning/src/general/scripts/aws/edge_configure.py
index 19269e0..d18798a 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/edge_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/edge_configure.py
@@ -232,14 +232,14 @@
         if os.environ['conf_letsencrypt_enabled'] == 'true' and 'conf_letsencrypt_domain_name' in os.environ:
             edge_conf['edge_hostname'] = '{}.{}'.format(edge_conf['project_name'], os.environ['conf_letsencrypt_domain_name'])
         else:
-            edge_conf['edge_hostname'] = "''"
+            edge_conf['edge_hostname'] = edge_conf['instance_hostname']
         keycloak_params = "--service_base_name {} --keycloak_auth_server_url {} --keycloak_realm_name {} " \
                           "--keycloak_user {} --keycloak_user_password {} --keycloak_client_secret {} " \
-                          "--instance_public_ip {} --hostname {} --project_name {} --endpoint_name {} --hostname {} ".format(
+                          "--instance_public_ip {} --project_name {} --endpoint_name {} --hostname {} ".format(
                            edge_conf['service_base_name'], os.environ['keycloak_auth_server_url'],
                            os.environ['keycloak_realm_name'], os.environ['keycloak_user'],
                            os.environ['keycloak_user_password'], edge_conf['keycloak_client_secret'],
-                           edge_conf['instance_hostname'], edge_conf['instance_hostname'], edge_conf['project_name'],
+                           edge_conf['instance_hostname'], edge_conf['project_name'],
                            edge_conf['endpoint_name'], edge_conf['edge_hostname'])
         try:
             subprocess.run("~/scripts/{}.py {}".format('configure_keycloak', keycloak_params), shell=True, check=True)
diff --git a/infrastructure-provisioning/src/general/scripts/aws/jupyter_configure.py b/infrastructure-provisioning/src/general/scripts/aws/jupyter_configure.py
index cba9911..bea8215 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/jupyter_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/jupyter_configure.py
@@ -32,6 +32,7 @@
 import subprocess
 from fabric import *
 from datalab.logger import logging
+import uuid
 
 parser = argparse.ArgumentParser()
 parser.add_argument('--uuid', type=str, default='')
@@ -42,7 +43,7 @@
     try:
         notebook_config = dict()
         try:
-            notebook_config['exploratory_name'] = os.environ['exploratory_name']
+            notebook_config['exploratory_name'] = os.environ['exploratory_name'].lower()
         except:
             notebook_config['exploratory_name'] = ''
         notebook_config['service_base_name'] = os.environ['conf_service_base_name']
@@ -296,6 +297,44 @@
             datalab.actions_lib.remove_ec2(notebook_config['tag_name'], notebook_config['instance_name'])
             sys.exit(1)
 
+    if os.environ['notebook_create_keycloak_client'] == 'True':
+        try:
+            logging.info('[SETUP KEYCLOAK CLIENT]')
+            notebook_config['keycloak_client_name'] = '{}-{}-{}-{}'\
+                .format(notebook_config['service_base_name'], notebook_config['project_name'],
+                        notebook_config['endpoint_name'], notebook_config['exploratory_name'])
+            notebook_config['keycloak_client_secret'] = str(uuid.uuid4())
+            keycloak_params = "--service_base_name {} --keycloak_auth_server_url {} --keycloak_realm_name {} " \
+                              "--keycloak_user {} --keycloak_user_password {} --keycloak_client_secret {} " \
+                              "--project_name {} --endpoint_name {} --exploratory_name {}"\
+                .format(notebook_config['service_base_name'], os.environ['keycloak_auth_server_url'],
+                        os.environ['keycloak_realm_name'], os.environ['keycloak_user'],
+                        os.environ['keycloak_user_password'], notebook_config['keycloak_client_secret'],
+                        notebook_config['project_name'], notebook_config['endpoint_name'],
+                        notebook_config['exploratory_name'])
+            try:
+                subprocess.run("~/scripts/{}.py {}".format('configure_keycloak', keycloak_params), shell=True, check=True)
+            except:
+                datalab.fab.append_result("Failed setup keycloak client")
+                raise Exception
+
+            try:
+                conn = datalab.fab.init_datalab_connection(instance_hostname, notebook_config['datalab_ssh_user'],
+                                                           notebook_config['ssh_key_path'], '', False)
+                content = json.loads(conn.sudo("cat /home/{}/.local/share/jupyter/kernels/py3spark_local/kernel.json"
+                                               .format(notebook_config['datalab_ssh_user'])).stdout)
+                content['env']['KEYCLOAK_CLIENT'] = notebook_config['keycloak_client_name']
+                content['env']['KEYCLOAK_SECRET'] = notebook_config['keycloak_client_secret']
+                conn.sudo("echo '{}' > /home/{}/.local/share/jupyter/kernels/py3spark_local/kernel.json"
+                          .format(json.dumps(content), notebook_config['datalab_ssh_user']))
+                conn.sudo('systemctl restart jupyter-notebook')
+            except:
+                datalab.fab.append_result("Failed to write variables to .bashrc")
+                raise Exception
+
+        except Exception as err:
+            datalab.fab.append_result("Failed setup keycloak client ", str(err))
+
     try:
         # generating output information
         ip_address = datalab.meta_lib.get_instance_ip_address(notebook_config['tag_name'],
diff --git a/infrastructure-provisioning/src/general/scripts/aws/jupyter_install_dataengine-service_kernels.py b/infrastructure-provisioning/src/general/scripts/aws/jupyter_install_dataengine-service_kernels.py
index 0efb00f..6e76b31 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/jupyter_install_dataengine-service_kernels.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/jupyter_install_dataengine-service_kernels.py
@@ -67,7 +67,7 @@
     conn.sudo('chmod 755 /usr/local/bin/jupyter_dataengine-service_create_configs.py')
     conn.sudo('mkdir -p /usr/lib/python3.8/datalab/')
     conn.run('mkdir -p /tmp/datalab_libs/')
-    subprocess.run('scp -i {} /usr/lib/python3.8/datalab/*.py {}@{}:/tmp/datalab_libs'.format(args.keyfile, args.os_user, args.notebook_ip), shell=True, check=True)
+    subprocess.run('rsync -e "ssh -i {}" /usr/lib/python3.8/datalab/*.py {}@{}:/tmp/datalab_libs'.format(args.keyfile, args.os_user, args.notebook_ip), shell=True, check=True)
     conn.run('chmod a+x /tmp/datalab_libs/*')
     conn.sudo('mv /tmp/datalab_libs/* /usr/lib/python3.8/datalab/')
     if exists(conn, '/usr/lib64'):
diff --git a/infrastructure-provisioning/src/general/scripts/aws/jupyterlab_configure.py b/infrastructure-provisioning/src/general/scripts/aws/jupyterlab_configure.py
index aa33a49..3d342ec 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/jupyterlab_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/jupyterlab_configure.py
@@ -42,7 +42,7 @@
     try:
         notebook_config = dict()
         try:
-            notebook_config['exploratory_name'] = os.environ['exploratory_name']
+            notebook_config['exploratory_name'] = os.environ['exploratory_name'].lower()
         except:
             notebook_config['exploratory_name'] = ''
         notebook_config['service_base_name'] = os.environ['conf_service_base_name']
diff --git a/infrastructure-provisioning/src/general/scripts/aws/project_prepare.py b/infrastructure-provisioning/src/general/scripts/aws/project_prepare.py
index aa271cd..c379503 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/project_prepare.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/project_prepare.py
@@ -62,6 +62,7 @@
                                                                       project_conf['project_name'],
                                                                       project_conf['endpoint_name'])
         project_conf['bucket_name'] = project_conf['bucket_name_tag'].lower().replace('_', '-')
+        project_conf['bucket_versioning_enabled'] = os.environ['conf_bucket_versioning_enabled']
         project_conf['shared_bucket_name_tag'] = '{0}-{1}-shared-bucket'.format(
             project_conf['service_base_name'], project_conf['endpoint_tag'])
         project_conf['shared_bucket_name'] = project_conf['shared_bucket_name_tag'].lower().replace('_', '-')
@@ -556,9 +557,9 @@
             project_conf['endpoint_tag'], os.environ['conf_billing_tag_key'], os.environ['conf_billing_tag_value'],
             project_conf['tag_name'], project_conf['shared_bucket_name'],
             project_conf['bucket_additional_tags']).replace(';', ',')
-        params = "--bucket_name {} --bucket_tags {} --region {} --bucket_name_tag {}". \
-            format(project_conf['shared_bucket_name'], project_conf['shared_bucket_tags'], project_conf['region'],
-                   project_conf['shared_bucket_name_tag'])
+        params = "--bucket_name {} --bucket_tags {} --region {} --bucket_name_tag {} --bucket_versioning_enabled {}" \
+            .format(project_conf['shared_bucket_name'], project_conf['shared_bucket_tags'], project_conf['region'],
+                    project_conf['shared_bucket_name_tag'], project_conf['bucket_versioning_enabled'])
         try:
             subprocess.run("~/scripts/{}.py {}".format('common_create_bucket', params), shell=True, check=True)
         except:
@@ -568,9 +569,9 @@
             project_conf['endpoint_tag'], os.environ['conf_billing_tag_key'], os.environ['conf_billing_tag_value'],
             project_conf['project_tag'], project_conf['tag_name'], project_conf['bucket_name'],
             project_conf['bucket_additional_tags']).replace(';', ',')
-        params = "--bucket_name {} --bucket_tags {} --region {} --bucket_name_tag {}" \
-                 .format(project_conf['bucket_name'], project_conf['bucket_tags'], project_conf['region'],
-                         project_conf['bucket_name_tag'])
+        params = "--bucket_name {} --bucket_tags {} --region {} --bucket_name_tag {} --bucket_versioning_enabled {}" \
+            .format(project_conf['bucket_name'], project_conf['bucket_tags'], project_conf['region'],
+                    project_conf['bucket_name_tag'], project_conf['bucket_versioning_enabled'])
         try:
             subprocess.run("~/scripts/{}.py {}".format('common_create_bucket', params), shell=True, check=True)
         except:
diff --git a/infrastructure-provisioning/src/general/scripts/aws/rstudio_configure.py b/infrastructure-provisioning/src/general/scripts/aws/rstudio_configure.py
index 505c867..20a0069 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/rstudio_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/rstudio_configure.py
@@ -49,7 +49,7 @@
     try:
         notebook_config = dict()
         try:
-            notebook_config['exploratory_name'] = os.environ['exploratory_name']
+            notebook_config['exploratory_name'] = os.environ['exploratory_name'].lower()
         except:
             notebook_config['exploratory_name'] = ''
         notebook_config['service_base_name'] = os.environ['conf_service_base_name']
diff --git a/infrastructure-provisioning/src/general/scripts/aws/rstudio_install_dataengine-service_kernels.py b/infrastructure-provisioning/src/general/scripts/aws/rstudio_install_dataengine-service_kernels.py
index 66eccb5..75d4db6 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/rstudio_install_dataengine-service_kernels.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/rstudio_install_dataengine-service_kernels.py
@@ -53,7 +53,7 @@
     conn.sudo('chmod 755 /usr/local/bin/rstudio_dataengine-service_create_configs.py')
     conn.sudo('mkdir -p /usr/lib/python3.8/datalab/')
     conn.run('mkdir -p /tmp/datalab_libs/')
-    conn.local('scp -i {} /usr/lib/python3.8/datalab/*.py {}@{}:/tmp/datalab_libs/'.format(args.keyfile, args.os_user, args.notebook_ip))
+    conn.local('rsync -e "ssh -i {}" /usr/lib/python3.8/datalab/*.py {}@{}:/tmp/datalab_libs/'.format(args.keyfile, args.os_user, args.notebook_ip))
     conn.run('chmod a+x /tmp/datalab_libs/*')
     conn.sudo('mv /tmp/datalab_libs/* /usr/lib/python3.8/datalab/')
     if exists(conn, '/usr/lib64'):
diff --git a/infrastructure-provisioning/src/general/scripts/aws/ssn_configure.py b/infrastructure-provisioning/src/general/scripts/aws/ssn_configure.py
index efc3a75..6be4a74 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/ssn_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/ssn_configure.py
@@ -148,7 +148,7 @@
     #installing prerequisites to ssn instance
     try:
         logging.info('[INSTALLING PREREQUISITES TO SSN INSTANCE]')
-        pip_packages = 'boto3=={} bcrypt=={} backoff=={} argparse=={} fabric=={} awscli=={} pymongo=={} pyyaml=={}' \
+        pip_packages = 'boto3=={} cryptography==36.0.2 bcrypt=={} backoff=={} argparse=={} fabric=={} awscli=={} pymongo=={} pyyaml=={}' \
                        ' jinja2=={}'.format(os.environ['pip_packages_boto3'], os.environ['pip_packages_bcrypt'],
                                             os.environ['pip_packages_backoff'], os.environ['pip_packages_argparse'],
                                             os.environ['pip_packages_fabric'], os.environ['pip_packages_awscli'],
@@ -203,6 +203,7 @@
                              {"name": "zeppelin", "tag": "latest"},
                              {"name": "tensor", "tag": "latest"},
                              {"name": "tensor-rstudio", "tag": "latest"},
+                             {"name": "tensor-jupyterlab", "tag": "latest"},
                              {"name": "jupyterlab", "tag": "latest"},
                              {"name": "deeplearning", "tag": "latest"},
                              {"name": "dataengine-service", "tag": "latest"},
@@ -522,7 +523,8 @@
                  "--tags {} " \
                  "--keycloak_client_id {} " \
                  "--keycloak_client_secret {} " \
-                 "--keycloak_auth_server_url {}". \
+                 "--keycloak_auth_server_url {} " \
+                 "--keycloak_realm_name {}". \
             format(ssn_conf['instance_hostname'],
                    "{}{}.pem".format(os.environ['conf_key_dir'], os.environ['conf_key_name']),
                    os.environ['ssn_datalab_path'],
@@ -551,7 +553,8 @@
                    os.environ['tags'],
                    os.environ['keycloak_client_name'],
                    os.environ['keycloak_client_secret'],
-                   os.environ['keycloak_auth_server_url'])
+                   os.environ['keycloak_auth_server_url'],
+                   os.environ['keycloak_realm_name'])
         try:
             subprocess.run("~/scripts/{}.py {}".format('configure_ui', params), shell=True, check=True)
         except:
diff --git a/infrastructure-provisioning/src/general/scripts/aws/ssn_prepare.py b/infrastructure-provisioning/src/general/scripts/aws/ssn_prepare.py
index 7e21cb1..8f094bb 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/ssn_prepare.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/ssn_prepare.py
@@ -257,19 +257,24 @@
 
     #creating roles
     try:
-        logging.info('[CREATE ROLES]')
-        params = "--role_name {} --role_profile_name {} --policy_name {} --policy_file_name {} --region {} " \
-                 "--infra_tag_name {} --infra_tag_value {} --user_tag_value {}". \
-            format(ssn_conf['role_name'], ssn_conf['role_profile_name'], ssn_conf['policy_name'],
-                   ssn_conf['policy_path'], ssn_conf['region'], ssn_conf['tag_name'],
-                   ssn_conf['service_base_name'], ssn_conf['user_tag'])
-        if 'aws_permissions_boundary_arn' in os.environ:
-            params = '{} --permissions_boundary_arn {}'.format(params, os.environ['aws_permissions_boundary_arn'])
-        try:
-            subprocess.run("~/scripts/{}.py {}".format('common_create_role_policy', params), shell=True, check=True)
-        except:
-            traceback.print_exc()
-            raise Exception
+        if 'aws_ssn_instance_role' in os.environ and os.environ['aws_ssn_instance_role'] != '':
+            logging.info('[USING PREDEFINED ROLE]')
+            ssn_conf['role_name'] = os.environ['aws_ssn_instance_role']
+            ssn_conf['role_profile_name'] = os.environ['aws_ssn_instance_role']
+        else:
+            logging.info('[CREATE ROLES]')
+            params = "--role_name {} --role_profile_name {} --policy_name {} --policy_file_name {} --region {} " \
+                     "--infra_tag_name {} --infra_tag_value {} --user_tag_value {}". \
+                format(ssn_conf['role_name'], ssn_conf['role_profile_name'], ssn_conf['policy_name'],
+                       ssn_conf['policy_path'], ssn_conf['region'], ssn_conf['tag_name'],
+                       ssn_conf['service_base_name'], ssn_conf['user_tag'])
+            if 'aws_permissions_boundary_arn' in os.environ:
+                params = '{} --permissions_boundary_arn {}'.format(params, os.environ['aws_permissions_boundary_arn'])
+            try:
+                subprocess.run("~/scripts/{}.py {}".format('common_create_role_policy', params), shell=True, check=True)
+            except:
+                traceback.print_exc()
+                raise Exception
     except Exception as err:
         logging.error('Error: {0}'.format(err))
         datalab.fab.append_result("Failed to create roles", str(err))
diff --git a/infrastructure-provisioning/src/general/scripts/aws/tensor-jupyterlab_configure.py b/infrastructure-provisioning/src/general/scripts/aws/tensor-jupyterlab_configure.py
new file mode 100644
index 0000000..9d3e785
--- /dev/null
+++ b/infrastructure-provisioning/src/general/scripts/aws/tensor-jupyterlab_configure.py
@@ -0,0 +1,338 @@
+#!/usr/bin/python3
+
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+import argparse
+import datalab.fab
+import datalab.actions_lib
+import datalab.meta_lib
+import json
+import os
+import sys
+import traceback
+import subprocess
+from fabric import *
+from datalab.logger import logging
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--uuid', type=str, default='')
+args = parser.parse_args()
+
+if __name__ == "__main__":
+    instance_class = 'notebook'
+    try:
+        notebook_config = dict()
+        try:
+            notebook_config['exploratory_name'] = os.environ['exploratory_name'].lower()
+        except:
+            notebook_config['exploratory_name'] = ''
+        notebook_config['service_base_name'] = os.environ['conf_service_base_name']
+        notebook_config['project_name'] = os.environ['project_name']
+        notebook_config['endpoint_name'] = os.environ['endpoint_name']
+        notebook_config['instance_type'] = os.environ['aws_notebook_instance_type']
+        notebook_config['key_name'] = os.environ['conf_key_name']
+        notebook_config['user_keyname'] = notebook_config['project_name']
+        notebook_config['network_type'] = os.environ['conf_network_type']
+        notebook_config['instance_name'] = '{}-{}-{}-nb-{}-{}'.format(notebook_config['service_base_name'],
+                                                                      notebook_config['project_name'],
+                                                                      notebook_config['endpoint_name'],
+                                                                      notebook_config['exploratory_name'], args.uuid)
+        notebook_config['image_enabled'] = os.environ['conf_image_enabled']
+        notebook_config['shared_image_enabled'] = os.environ['conf_shared_image_enabled']
+        if os.environ['conf_shared_image_enabled'] == 'false':
+            notebook_config['expected_image_name'] = '{0}-{1}-{2}-{3}-notebook-image'.format(
+                notebook_config['service_base_name'],
+                notebook_config['project_name'],
+                notebook_config['endpoint_name'],
+                os.environ['application'])
+        else:
+            notebook_config['expected_image_name'] = '{0}-{1}-{2}-notebook-image'.format(
+                notebook_config['service_base_name'],
+                notebook_config['endpoint_name'],
+                os.environ['application'])
+        notebook_config['notebook_image_name'] = str(os.environ.get('notebook_image_name'))
+        notebook_config['role_profile_name'] = '{}-{}-{}-nb-de-profile'.format(
+            notebook_config['service_base_name'], notebook_config['project_name'], notebook_config['endpoint_name'])
+        notebook_config['security_group_name'] = '{}-{}-{}-nb-sg'.format(notebook_config['service_base_name'],
+                                                                         notebook_config['project_name'],
+                                                                         notebook_config['endpoint_name'])
+        notebook_config['tag_name'] = '{}-tag'.format(notebook_config['service_base_name'])
+        notebook_config['datalab_ssh_user'] = os.environ['conf_os_user']
+        notebook_config['ip_address'] = datalab.meta_lib.get_instance_ip_address(
+            notebook_config['tag_name'], notebook_config['instance_name']).get('Private')
+
+        # generating variables regarding EDGE proxy on Notebook instance
+        instance_hostname = datalab.meta_lib.get_instance_hostname(notebook_config['tag_name'],
+                                                                   notebook_config['instance_name'])
+        edge_instance_name = '{}-{}-{}-edge'.format(notebook_config['service_base_name'],
+                                                    notebook_config['project_name'], notebook_config['endpoint_name'])
+        edge_instance_hostname = datalab.meta_lib.get_instance_hostname(notebook_config['tag_name'], edge_instance_name)
+        edge_instance_private_ip = datalab.meta_lib.get_instance_ip_address(notebook_config['tag_name'],
+                                                                            edge_instance_name).get('Private')
+        notebook_config['edge_instance_hostname'] = datalab.meta_lib.get_instance_hostname(notebook_config['tag_name'],
+                                                                                           edge_instance_name)
+        keyfile_name = "{}{}.pem".format(os.environ['conf_key_dir'], os.environ['conf_key_name'])
+        edge_ip = datalab.meta_lib.get_instance_ip_address(notebook_config['tag_name'], edge_instance_name).get(
+            'Private')
+    except Exception as err:
+        datalab.fab.append_result("Failed to generate variables dictionary.", str(err))
+        datalab.actions_lib.remove_ec2(notebook_config['tag_name'], notebook_config['instance_name'])
+        sys.exit(1)
+
+    try:
+        if os.environ['conf_os_family'] == 'debian':
+            notebook_config['initial_user'] = 'ubuntu'
+            notebook_config['sudo_group'] = 'sudo'
+        if os.environ['conf_os_family'] == 'redhat':
+            notebook_config['initial_user'] = 'ec2-user'
+            notebook_config['sudo_group'] = 'wheel'
+
+        logging.info('[CREATING DATALAB SSH USER]')
+        params = "--hostname {} --keyfile {} --initial_user {} --os_user {} --sudo_group {}".format(
+            instance_hostname, "{}{}.pem".format(os.environ['conf_key_dir'], os.environ['conf_key_name']),
+            notebook_config['initial_user'], notebook_config['datalab_ssh_user'], notebook_config['sudo_group'])
+
+        try:
+            subprocess.run("~/scripts/{}.py {}".format('create_ssh_user', params), shell=True, check=True)
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        datalab.fab.append_result("Failed creating ssh user 'datalab'.", str(err))
+        datalab.actions_lib.remove_ec2(notebook_config['tag_name'], notebook_config['instance_name'])
+        sys.exit(1)
+
+    # configuring proxy on Notebook instance
+    try:
+        logging.info('[CONFIGURE PROXY ON TENSOR INSTANCE]')
+        additional_config = {"proxy_host": edge_instance_hostname, "proxy_port": "3128"}
+        params = "--hostname {} --instance_name {} --keyfile {} --additional_config '{}' --os_user {}"\
+            .format(instance_hostname, notebook_config['instance_name'], keyfile_name, json.dumps(additional_config),
+                    notebook_config['datalab_ssh_user'])
+        try:
+            subprocess.run("~/scripts/{}.py {}".format('common_configure_proxy', params), shell=True, check=True)
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        datalab.fab.append_result("Failed to configure proxy.", str(err))
+        datalab.actions_lib.remove_ec2(notebook_config['tag_name'], notebook_config['instance_name'])
+        sys.exit(1)
+
+    # updating repositories & installing python packages
+    try:
+        logging.info('[INSTALLING PREREQUISITES TO JUPYTERLAB TENSORFLOW NOTEBOOK INSTANCE]')
+        params = "--hostname {} --keyfile {} --user {} --region {} --edge_private_ip {}". \
+            format(instance_hostname, keyfile_name, notebook_config['datalab_ssh_user'], os.environ['aws_region'],
+                   edge_instance_private_ip)
+        try:
+            subprocess.run("~/scripts/{}.py {}".format('install_prerequisites', params), shell=True, check=True)
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        datalab.fab.append_result("Failed installing apps: apt & pip.", str(err))
+        datalab.actions_lib.remove_ec2(notebook_config['tag_name'], notebook_config['instance_name'])
+        sys.exit(1)
+
+    # installing and configuring TensorFlow and all dependencies
+    try:
+        logging.info('[CONFIGURE JUPYTERLAB TENSORFLOW NOTEBOOK INSTANCE]')
+        params = "--hostname {0} --keyfile {1} " \
+                 "--region {2} --os_user {3} " \
+                 "--ip_address {4} --exploratory_name {5} --edge_ip {6}" \
+                 .format(instance_hostname, keyfile_name,
+                         os.environ['aws_region'], notebook_config['datalab_ssh_user'],
+                         notebook_config['ip_address'], notebook_config['exploratory_name'], edge_ip)
+        try:
+            subprocess.run("~/scripts/{}.py {}".format('configure_tensor-jupyterlab_node', params), shell=True, check=True)
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        datalab.fab.append_result("Failed to configure TensorFlow.", str(err))
+        datalab.actions_lib.remove_ec2(notebook_config['tag_name'], notebook_config['instance_name'])
+        sys.exit(1)
+
+    try:
+        logging.info('[INSTALLING USERs KEY]')
+        additional_config = {"user_keyname": notebook_config['user_keyname'],
+                             "user_keydir": os.environ['conf_key_dir']}
+        params = "--hostname {} --keyfile {} --additional_config '{}' --user {}".format(
+            instance_hostname, keyfile_name, json.dumps(additional_config), notebook_config['datalab_ssh_user'])
+        try:
+            subprocess.run("~/scripts/{}.py {}".format('install_user_key', params), shell=True, check=True)
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        datalab.fab.append_result("Failed installing users key.", str(err))
+        datalab.actions_lib.remove_ec2(notebook_config['tag_name'], notebook_config['instance_name'])
+        sys.exit(1)
+
+    try:
+        logging.info('[SETUP USER GIT CREDENTIALS]')
+        params = '--os_user {} --notebook_ip {} --keyfile "{}"' \
+            .format(notebook_config['datalab_ssh_user'], instance_hostname, keyfile_name)
+        try:
+            subprocess.run("~/scripts/{}.py {}".format('manage_git_creds', params), shell=True, check=True)
+        except:
+            datalab.fab.append_result("Failed setup git credentials")
+            raise Exception
+    except Exception as err:
+        datalab.fab.append_result("Failed to setup git credentials.", str(err))
+        datalab.actions_lib.remove_ec2(notebook_config['tag_name'], notebook_config['instance_name'])
+        sys.exit(1)
+
+    try:
+        logging.info('[POST CONFIGURING PROCESS]')
+        if notebook_config['notebook_image_name'] not in [notebook_config['expected_image_name'], 'None', '']:
+            params = "--hostname {} --keyfile {} --os_user {} --nb_tag_name {} --nb_tag_value {}" \
+                .format(instance_hostname, keyfile_name, notebook_config['datalab_ssh_user'],
+                        notebook_config['tag_name'], notebook_config['instance_name'])
+            try:
+                subprocess.run("~/scripts/{}.py {}".format('common_remove_remote_kernels', params), shell=True, check=True)
+            except:
+                traceback.print_exc()
+                raise Exception
+    except Exception as err:
+        datalab.fab.append_result("Failed to post configuring instance.", str(err))
+        datalab.actions_lib.remove_ec2(notebook_config['tag_name'], notebook_config['instance_name'])
+        sys.exit(1)
+
+    try:
+        logging.info('[SETUP EDGE REVERSE PROXY TEMPLATE]')
+        additional_info = {
+            'instance_hostname': instance_hostname,
+            'tensor': True
+        }
+        params = "--edge_hostname {} --keyfile {} --os_user {} --type {} --exploratory_name {} --additional_info '{}'" \
+            .format(edge_instance_hostname, keyfile_name, notebook_config['datalab_ssh_user'], 'jupyter',
+                    notebook_config['exploratory_name'], json.dumps(additional_info))
+        try:
+            subprocess.run("~/scripts/{}.py {}".format('common_configure_reverse_proxy', params), shell=True, check=True)
+        except:
+            datalab.fab.append_result("Failed edge reverse proxy template")
+            raise Exception
+    except Exception as err:
+        datalab.fab.append_result("Failed to set edge reverse proxy template.", str(err))
+        datalab.actions_lib.remove_ec2(notebook_config['tag_name'], notebook_config['instance_name'])
+        sys.exit(1)
+
+    if notebook_config['image_enabled'] == 'true':
+        try:
+            logging.info('[CREATING AMI]')
+            ami_id = datalab.meta_lib.get_ami_id_by_name(notebook_config['expected_image_name'])
+            if ami_id == '' and notebook_config['shared_image_enabled'] == 'false':
+                logging.info("Looks like it's first time we configure notebook server. Creating image.")
+                try:
+                    os.environ['conf_additional_tags'] = '{2};project_tag:{0};endpoint_tag:{1};'.format(
+                        os.environ['project_name'], os.environ['endpoint_name'], os.environ['conf_additional_tags'])
+                except KeyError:
+                    os.environ['conf_additional_tags'] = 'project_tag:{0};endpoint_tag:{1}'.format(
+                        os.environ['project_name'], os.environ['endpoint_name'])
+                image_id = datalab.actions_lib.create_image_from_instance(
+                    tag_name=notebook_config['tag_name'], instance_name=notebook_config['instance_name'],
+                    image_name=notebook_config['expected_image_name'])
+                if image_id != '':
+                    logging.info("Image was successfully created. It's ID is {}".format(image_id))
+            else:
+                logging.info("Looks like it's first time we configure notebook server. Creating image.")
+                try:
+                    os.environ['conf_additional_tags'] = '{};ami:shared;endpoint_tag:{};'.format(
+                        os.environ['conf_additional_tags'], os.environ['endpoint_name'])
+                except KeyError:
+                    os.environ['conf_additional_tags'] = 'ami:shared;endpoint_tag:{}'.format(
+                        os.environ['endpoint_name'])
+                image_id = datalab.actions_lib.create_image_from_instance(
+                    tag_name=notebook_config['tag_name'], instance_name=notebook_config['instance_name'],
+                    image_name=notebook_config['expected_image_name'])
+                if image_id != '':
+                    logging.info("Image was successfully created. It's ID is {}".format(image_id))
+        except Exception as err:
+            datalab.fab.append_result("Failed creating image.", str(err))
+            datalab.actions_lib.remove_ec2(notebook_config['tag_name'], notebook_config['instance_name'])
+            sys.exit(1)
+    try:
+        # generating output information
+        ip_address = datalab.meta_lib.get_instance_ip_address(notebook_config['tag_name'],
+                                                              notebook_config['instance_name']).get('Private')
+        dns_name = datalab.meta_lib.get_instance_hostname(notebook_config['tag_name'], notebook_config['instance_name'])
+        tensorboard_url = "http://" + ip_address + ":6006/"
+        jupyter_ip_url = "http://" + ip_address + ":8888/{}/".format(notebook_config['exploratory_name'])
+        jupyter_notebook_access_url = "https://{}/{}/".format(notebook_config['edge_instance_hostname'],
+                                                              notebook_config['exploratory_name'])
+        tensorboard_access_url = "https://{}/{}-tensor/".format(notebook_config['edge_instance_hostname'],
+                                                                notebook_config['exploratory_name'])
+        jupyter_ungit_access_url = "https://{}/{}-ungit/".format(notebook_config['edge_instance_hostname'],
+                                                                 notebook_config['exploratory_name'])
+        ungit_ip_url = "http://" + ip_address + ":8085/{}-ungit/".format(notebook_config['exploratory_name'])
+        logging.info('[SUMMARY]')
+        logging.info("Instance name: {}".format(notebook_config['instance_name']))
+        logging.info("Private DNS: {}".format(dns_name))
+        logging.info("Private IP: {}".format(ip_address))
+        logging.info("Instance ID: {}".format(datalab.meta_lib.get_instance_by_name(notebook_config['tag_name'],
+                                                                             notebook_config['instance_name'])))
+        logging.info("Instance type: {}".format(notebook_config['instance_type']))
+        logging.info("Key name: {}".format(notebook_config['key_name']))
+        logging.info("User key name: {}".format(notebook_config['user_keyname']))
+        logging.info("AMI name: {}".format(notebook_config['notebook_image_name']))
+        logging.info("Profile name: {}".format(notebook_config['role_profile_name']))
+        logging.info("SG name: {}".format(notebook_config['security_group_name']))
+        logging.info("TensorBoard URL: {}".format(tensorboard_url))
+        logging.info("TensorBoard log dir: /var/log/tensorboard")
+        logging.info("Jupyter URL: {}".format(jupyter_ip_url))
+        logging.info("Ungit URL: {}".format(ungit_ip_url))
+        logging.info('SSH access (from Edge node, via IP address): ssh -i {0}.pem {1}@{2}'.format(
+            notebook_config['key_name'], notebook_config['datalab_ssh_user'], ip_address))
+        logging.info('SSH access (from Edge node, via FQDN): ssh -i {0}.pem {1}@{2}'.format(
+            notebook_config['key_name'], notebook_config['datalab_ssh_user'], dns_name))
+
+        with open("/root/result.json", 'w') as result:
+            res = {"hostname": dns_name,
+                   "ip": ip_address,
+                   "instance_id": datalab.meta_lib.get_instance_by_name(notebook_config['tag_name'],
+                                                                        notebook_config['instance_name']),
+                   "master_keyname": os.environ['conf_key_name'],
+                   "tensorboard_log_dir": "/var/log/tensorboard",
+                   "notebook_name": notebook_config['instance_name'],
+                   "notebook_image_name": notebook_config['notebook_image_name'],
+                   "Action": "Create new notebook server",
+                   "exploratory_url": [
+                       {"description": "Jupyterlab",
+                        "url": jupyter_notebook_access_url},
+                       {"description": "Ungit",
+                        "url": jupyter_ungit_access_url}#,
+                       # {"description": "TensorBoard",
+                       #  "url": tensorboard_access_url},
+                       #{"description": "Jupyter (via tunnel)",
+                       # "url": jupyter_ip_url},
+                       #{"description": "TensorBoard (via tunnel)",
+                       # "url": tensorboard_url},
+                       #{"description": "Ungit (via tunnel)",
+                       # "url": ungit_ip_url}
+                   ]}
+            result.write(json.dumps(res))
+    except Exception as err:
+        datalab.fab.append_result("Error with writing results.", str(err))
+        datalab.actions_lib.remove_ec2(notebook_config['tag_name'], notebook_config['instance_name'])
+        sys.exit(1)
diff --git a/infrastructure-provisioning/src/general/scripts/aws/tensor-rstudio_configure.py b/infrastructure-provisioning/src/general/scripts/aws/tensor-rstudio_configure.py
index c51b09f..a7b2eed 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/tensor-rstudio_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/tensor-rstudio_configure.py
@@ -42,7 +42,7 @@
     try:
         notebook_config = dict()
         try:
-            notebook_config['exploratory_name'] = os.environ['exploratory_name']
+            notebook_config['exploratory_name'] = os.environ['exploratory_name'].lower()
         except:
             notebook_config['exploratory_name'] = ''
         notebook_config['service_base_name'] = os.environ['conf_service_base_name']
diff --git a/infrastructure-provisioning/src/general/scripts/aws/tensor_configure.py b/infrastructure-provisioning/src/general/scripts/aws/tensor_configure.py
index 2a0d115..a0940fc 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/tensor_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/tensor_configure.py
@@ -42,7 +42,7 @@
     try:
         notebook_config = dict()
         try:
-            notebook_config['exploratory_name'] = os.environ['exploratory_name']
+            notebook_config['exploratory_name'] = os.environ['exploratory_name'].lower()
         except:
             notebook_config['exploratory_name'] = ''
         notebook_config['service_base_name'] = os.environ['conf_service_base_name']
@@ -154,6 +154,22 @@
         datalab.actions_lib.remove_ec2(notebook_config['tag_name'], notebook_config['instance_name'])
         sys.exit(1)
 
+    #Installing GPU drivers
+    try:
+        logging.info('[INSTALLING GPU DRIVERS]')
+        params = "--hostname {} --keyfile {} --os_user {}".format(
+            instance_hostname, keyfile_name, notebook_config['datalab_ssh_user'])
+        try:
+            subprocess.run("~/scripts/{}.py {}".format('common_install_gpu', params), shell=True, check=True)
+        except:
+            datalab.fab.append_result("Failed installing users key")
+            raise Exception
+
+    except Exception as err:
+        datalab.fab.append_result("Failed to install GPU drivers.", str(err))
+        GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
+        sys.exit(1)
+
     # installing and configuring TensorFlow and all dependencies
     try:
         logging.info('[CONFIGURE TENSORFLOW NOTEBOOK INSTANCE]')
diff --git a/infrastructure-provisioning/src/general/scripts/aws/zeppelin_configure.py b/infrastructure-provisioning/src/general/scripts/aws/zeppelin_configure.py
index 3a12ee6..ff945ba 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/zeppelin_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/zeppelin_configure.py
@@ -42,7 +42,7 @@
     try:
         notebook_config = dict()
         try:
-            notebook_config['exploratory_name'] = os.environ['exploratory_name']
+            notebook_config['exploratory_name'] = os.environ['exploratory_name'].lower()
         except:
             notebook_config['exploratory_name'] = ''
         notebook_config['service_base_name'] = os.environ['conf_service_base_name']
diff --git a/infrastructure-provisioning/src/general/scripts/aws/zeppelin_dataengine-service_create_configs.py b/infrastructure-provisioning/src/general/scripts/aws/zeppelin_dataengine-service_create_configs.py
index 4f6e073..4ad2b36 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/zeppelin_dataengine-service_create_configs.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/zeppelin_dataengine-service_create_configs.py
@@ -37,6 +37,7 @@
 parser.add_argument('--spark_version', type=str, default='')
 parser.add_argument('--scala_version', type=str, default='')
 parser.add_argument('--hadoop_version', type=str, default='')
+parser.add_argument('--matplotlib_version', type=str, default='')
 parser.add_argument('--region', type=str, default='')
 parser.add_argument('--excluded_lines', type=str, default='')
 parser.add_argument('--project_name', type=str, default='')
@@ -45,7 +46,6 @@
 parser.add_argument('--proxy_port', type=str, default='')
 parser.add_argument('--livy_version', type=str, default='')
 parser.add_argument('--multiple_clusters', type=str, default='')
-parser.add_argument('--pip_mirror', type=str, default='')
 parser.add_argument('--numpy_version', type=str, default='')
 parser.add_argument('--application', type=str, default='')
 parser.add_argument('--r_enabled', type=str, default='')
@@ -94,7 +94,7 @@
         if args.multiple_clusters == 'true':
             install_remote_livy(args)
         installing_python(args.region, args.bucket, args.project_name, args.cluster_name, args.application,
-                          args.pip_mirror, args.numpy_version)
+                          args.numpy_version, args.matplotlib_version)
         configure_zeppelin_emr_interpreter(args.emr_version, args.cluster_name, args.region, spark_dir, args.os_user,
                                            yarn_dir, args.bucket, args.project_name, endpoint_url, args.multiple_clusters)
         update_zeppelin_interpreters(args.multiple_clusters, args.r_enabled)
diff --git a/infrastructure-provisioning/src/general/scripts/aws/zeppelin_install_dataengine-service_kernels.py b/infrastructure-provisioning/src/general/scripts/aws/zeppelin_install_dataengine-service_kernels.py
index 96615dc..df9c51a 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/zeppelin_install_dataengine-service_kernels.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/zeppelin_install_dataengine-service_kernels.py
@@ -40,7 +40,6 @@
 parser.add_argument('--os_user', type=str, default='')
 parser.add_argument('--edge_hostname', type=str, default='')
 parser.add_argument('--proxy_port', type=str, default='')
-parser.add_argument('--pip_mirror', type=str, default='')
 parser.add_argument('--application', type=str, default='')
 args = parser.parse_args()
 
@@ -59,7 +58,7 @@
     conn.sudo('chmod 755 /usr/local/bin/zeppelin_dataengine-service_create_configs.py')
     conn.sudo('mkdir -p /usr/lib/python3.8/datalab/')
     conn.run('mkdir -p /tmp/datalab_libs/')
-    conn.local('scp -i {} /usr/lib/python3.8/datalab/*.py {}@{}:/tmp/datalab_libs/'.format(args.keyfile, args.os_user, args.notebook_ip))
+    conn.local('rsync -e "ssh -i {}" /usr/lib/python3.8/datalab/*.py {}@{}:/tmp/datalab_libs/'.format(args.keyfile, args.os_user, args.notebook_ip))
     conn.run('chmod a+x /tmp/datalab_libs/*')
     conn.sudo('mv /tmp/datalab_libs/* /usr/lib/python3.8/datalab/')
     if exists(conn, '/usr/lib64'):
@@ -76,6 +75,7 @@
     livy_version = os.environ['notebook_livy_version']
     r_enabled = os.environ['notebook_r_enabled']
     numpy_version = os.environ['notebook_numpy_version']
+    matplotlib_version = os.environ['notebook_matplotlib_version']
     command = "/usr/bin/python3 /usr/local/bin/zeppelin_dataengine-service_create_configs.py " \
              "--bucket {0} " \
              "--cluster_name {1} " \
@@ -91,8 +91,8 @@
              "--scala_version {11} " \
              "--livy_version {12} " \
              "--multiple_clusters {13} " \
-             "--pip_mirror {14} " \
-             "--numpy_version {15} " \
+             "--numpy_version {14} " \
+             "--matplotlib_version {15} " \
              "--application {16} " \
              "--r_enabled {17}" \
         .format(args.bucket,
@@ -109,8 +109,8 @@
                 args.scala_version,
                 livy_version,
                 os.environ['notebook_multiple_clusters'],
-                args.pip_mirror,
                 numpy_version,
+                matplotlib_version,
                 args.application,
                 r_enabled)
-    conn.sudo(command)
\ No newline at end of file
+    conn.sudo(command)
diff --git a/infrastructure-provisioning/src/general/scripts/azure/common_collect_data.py b/infrastructure-provisioning/src/general/scripts/azure/common_collect_data.py
index ee8eda7..71cdf86 100644
--- a/infrastructure-provisioning/src/general/scripts/azure/common_collect_data.py
+++ b/infrastructure-provisioning/src/general/scripts/azure/common_collect_data.py
@@ -46,6 +46,16 @@
             statuses['host'] = data_instances
         except:
             logging.error("Hosts JSON wasn't been provided")
+        try:
+            data_images = AzureMeta().get_image_statuses(args.resource_group_name, data.get('image'))
+            statuses['image'] = data_images
+        except:
+            logging.error("Images JSON wasn't been provided")
+        try:
+            data_clusters = AzureMeta().list_hdinsight_statuses(args.resource_group_name, data.get('cluster'))
+            statuses['cluster'] = data_clusters
+        except:
+            logging.error("Clusters JSON wasn't been provided")
         with open('/root/result.json', 'w') as outfile:
             json.dump(statuses, outfile)
     except Exception as err:
diff --git a/infrastructure-provisioning/src/general/scripts/azure/common_create_instance.py b/infrastructure-provisioning/src/general/scripts/azure/common_create_instance.py
index 3f284d3..e4677a0 100644
--- a/infrastructure-provisioning/src/general/scripts/azure/common_create_instance.py
+++ b/infrastructure-provisioning/src/general/scripts/azure/common_create_instance.py
@@ -95,6 +95,9 @@
                                                args.project_name,
                                                create_option, disk_id, args.instance_storage_account_type,
                                                args.image_type)
+                for disk in AzureMeta().list_disks(args.resource_group_name):
+                    if "SBN" in disk.tags and args.service_base_name == disk.tags["SBN"]:
+                        AzureActions().update_disk_access(resource_group_name=args.resource_group_name, disk_name=disk.name)
         except Exception as err:
             logging.error('Error: {0}'.format(err))
             sys.exit(1)
diff --git a/infrastructure-provisioning/src/general/scripts/azure/common_create_notebook_image.py b/infrastructure-provisioning/src/general/scripts/azure/common_create_notebook_image.py
index a3cddbd..a50be7d 100644
--- a/infrastructure-provisioning/src/general/scripts/azure/common_create_notebook_image.py
+++ b/infrastructure-provisioning/src/general/scripts/azure/common_create_notebook_image.py
@@ -46,7 +46,7 @@
         image_conf['instance_name'] = os.environ['notebook_instance_name']
         image_conf['application'] = os.environ['application']
         image_conf['datalab_ssh_user'] = os.environ['conf_os_user']
-        image_conf['image_name'] = os.environ['notebook_image_name']
+        image_conf['image_name'] = os.environ['notebook_image_name'].replace('_', '-')
         image_conf['full_image_name'] = '{}-{}-{}-{}-{}'.format(image_conf['service_base_name'],
                                                                 image_conf['project_name'],
                                                                 image_conf['endpoint_name'],
@@ -119,7 +119,7 @@
                        "user_name": image_conf['user_name'],
                        "project_name": image_conf['project_name'],
                        "application": image_conf['application'],
-                       "status": "created",
+                       "status": "active",
                        "Action": "Create image from notebook"}
                 result.write(json.dumps(res))
     except Exception as err:
diff --git a/infrastructure-provisioning/src/general/scripts/azure/common_create_storage_account.py b/infrastructure-provisioning/src/general/scripts/azure/common_create_storage_account.py
index 17676b0..8c94592 100644
--- a/infrastructure-provisioning/src/general/scripts/azure/common_create_storage_account.py
+++ b/infrastructure-provisioning/src/general/scripts/azure/common_create_storage_account.py
@@ -34,6 +34,7 @@
 parser.add_argument('--account_tags', type=str, default='{"empty":"string"}')
 parser.add_argument('--resource_group_name', type=str, default='')
 parser.add_argument('--region', type=str, default='')
+parser.add_argument('--storage_account_kind', type=str, default='BlobStorage')
 args = parser.parse_args()
 
 if __name__ == "__main__":
@@ -50,9 +51,9 @@
             if check.name_available:
                 logging.info("Creating storage account {}.".format(account_name))
                 storage_account = AzureActions().create_storage_account(args.resource_group_name, account_name,
-                                                                        args.region, account_tags)
-                blob_container = AzureActions().create_blob_container(args.resource_group_name, account_name,
-                                                                      args.container_name)
+                                                                        args.region, account_tags,
+                                                                        args.storage_account_kind)
+                blob_container = AzureActions().create_blob_container(account_name, args.container_name)
                 logging.info("STORAGE ACCOUNT {} has been created".format(account_name))
                 logging.info("CONTAINER {} has been created".format(args.container_name))
             else:
diff --git a/infrastructure-provisioning/src/general/scripts/azure/common_notebook_configure_dataengine-service.py b/infrastructure-provisioning/src/general/scripts/azure/common_notebook_configure_dataengine-service.py
new file mode 100644
index 0000000..31e9dca
--- /dev/null
+++ b/infrastructure-provisioning/src/general/scripts/azure/common_notebook_configure_dataengine-service.py
@@ -0,0 +1,139 @@
+#!/usr/bin/python3
+
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+import datalab.fab
+import datalab.actions_lib
+import datalab.meta_lib
+import json
+from datalab.logger import logging
+import os
+import sys
+import traceback
+import subprocess
+from fabric import *
+
+
+def clear_resources():
+    AzureActions.terminate_hdinsight_cluster(notebook_config['resource_group_name'],
+                                             notebook_config['full_cluster_name'])
+    for storage_account in AzureMeta.list_storage_accounts(notebook_config['resource_group_name']):
+        if notebook_config['storage_account_name_tag'] == storage_account.tags["Name"]:
+            AzureActions.remove_storage_account(notebook_config['resource_group_name'], storage_account.name)
+    AzureActions.remove_dataengine_kernels(notebook_config['resource_group_name'],
+                                           notebook_config['notebook_name'], os.environ['conf_os_user'],
+                                           notebook_config['key_path'], notebook_config['cluster_name'])
+
+
+if __name__ == "__main__":
+    # generating variables dictionary
+    AzureMeta = datalab.meta_lib.AzureMeta()
+    AzureActions = datalab.actions_lib.AzureActions()
+    logging.info('Generating infrastructure names and tags')
+    notebook_config = dict()
+    notebook_config['resource_group_name'] = os.environ['azure_resource_group_name']
+    notebook_config['service_base_name'] = (os.environ['conf_service_base_name'])
+    notebook_config['notebook_name'] = os.environ['notebook_instance_name']
+    notebook_config['edge_user_name'] = (os.environ['edge_user_name'])
+    notebook_config['project_name'] = (os.environ['project_name']).replace('_', '-').lower()
+    notebook_config['project_tag'] = notebook_config['project_name']
+    notebook_config['endpoint_name'] = (os.environ['endpoint_name']).replace('_', '-').lower()
+    notebook_config['endpoint_tag'] = notebook_config['endpoint_name']
+    notebook_config['tag_name'] = notebook_config['service_base_name'] + '-tag'
+    notebook_config['computational_name'] = os.environ['computational_name'].replace('_', '-').lower()
+    notebook_config['bucket_name'] = '{0}-{1}-{2}-bucket'.format(notebook_config['service_base_name'],
+                                                                 notebook_config['project_name'],
+                                                                 notebook_config['endpoint_name'])
+    notebook_config['cluster_name'] = '{}-{}-{}-des-{}'.format(notebook_config['service_base_name'],
+                                                              notebook_config['project_name'],
+                                                              notebook_config['endpoint_name'],
+                                                              notebook_config['computational_name'])
+    notebook_config['storage_account_name_tag'] = ('{}-bucket'.format(notebook_config['cluster_name'])).lower()
+    notebook_config['notebook_ip'] = AzureMeta.get_private_ip_address(notebook_config['resource_group_name'],
+                                                                      notebook_config['notebook_name'])
+    notebook_config['key_path'] = '{0}{1}.pem'.format(os.environ['conf_key_dir'], os.environ['conf_key_name'])
+    edge_instance_name = '{0}-{1}-{2}-edge'.format(notebook_config['service_base_name'],
+                                                   notebook_config['project_name'], notebook_config['endpoint_tag'])
+    edge_instance_hostname = AzureMeta.get_private_ip_address(notebook_config['resource_group_name'],
+                                                              edge_instance_name)
+    for cluster in AzureMeta.list_hdinsight_clusters(notebook_config['resource_group_name']):
+        if notebook_config['cluster_name'] == cluster.tags["Name"]:
+            notebook_config['full_cluster_name'] = cluster.name
+    notebook_config['headnode_ip'] = datalab.fab.get_hdinsight_headnode_private_ip(os.environ['conf_os_user'],
+                                                                                   notebook_config['full_cluster_name'],
+                                                                                   notebook_config['key_path'])
+
+    if os.environ['application'] == 'deeplearning':
+        application = 'jupyter'
+    else:
+        application = os.environ['application']
+
+    try:
+        logging.info('[INSTALLING KERNELS INTO SPECIFIED NOTEBOOK]')
+        params = "--bucket {} --cluster_name {} --hdinsight_version {} --keyfile {} --notebook_ip {} --region {} " \
+                 "--project_name {} --os_user {}  --edge_hostname {} --proxy_port {} " \
+                 "--scala_version {} --application {} --headnode_ip {}" \
+            .format(notebook_config['storage_account_name_tag'], notebook_config['full_cluster_name'], os.environ['hdinsight_version'],
+                    notebook_config['key_path'], notebook_config['notebook_ip'], os.environ['gcp_region'],
+                    notebook_config['project_name'], os.environ['conf_os_user'],
+                    edge_instance_hostname, '3128', os.environ['notebook_scala_version'], os.environ['application'],
+                    notebook_config['headnode_ip'])
+        try:
+            subprocess.run("~/scripts/{}_{}.py {}".format(application, 'install_dataengine-service_kernels', params), 
+                           shell=True, check=True)
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        clear_resources()
+        datalab.fab.append_result("Failed installing HDinsight kernels.", str(err))
+        sys.exit(1)
+
+    try:
+        logging.info('[UPDATING SPARK CONFIGURATION FILES ON NOTEBOOK]')
+        params = "--hostname {0} " \
+                 "--keyfile {1} " \
+                 "--os_user {2} " \
+            .format(notebook_config['notebook_ip'],
+                    notebook_config['key_path'],
+                    os.environ['conf_os_user'])
+        try:
+            subprocess.run("~/scripts/{0}.py {1}".format('common_configure_spark', params), shell=True, check=True)
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        datalab.fab.append_result("Failed to configure Spark.", str(err))
+        clear_resources()
+        sys.exit(1)
+
+    try:
+        with open("/root/result.json", 'w') as result:
+            res = {"notebook_name": notebook_config['notebook_name'],
+                   "Tag_name": notebook_config['tag_name'],
+                   "Action": "Configure notebook server"}
+            logging.info(json.dumps(res))
+            result.write(json.dumps(res))
+    except Exception as err:
+        datalab.fab.append_result("Error with writing results", str(err))
+        clear_resources()
+        sys.exit(1)
diff --git a/infrastructure-provisioning/src/general/scripts/azure/common_prepare_notebook.py b/infrastructure-provisioning/src/general/scripts/azure/common_prepare_notebook.py
index 27dfcb8..206c291 100644
--- a/infrastructure-provisioning/src/general/scripts/azure/common_prepare_notebook.py
+++ b/infrastructure-provisioning/src/general/scripts/azure/common_prepare_notebook.py
@@ -9,9 +9,9 @@
 # to you under the Apache License, Version 2.0 (the
 # "License"); you may not use this file except in compliance
 # with the License.  You may obtain a copy of the License at
-# 
+#
 #   http://www.apache.org/licenses/LICENSE-2.0
-# 
+#
 # Unless required by applicable law or agreed to in writing,
 # software distributed under the License is distributed on an
 # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -68,6 +68,11 @@
                                    "endpoint_tag": notebook_config['endpoint_tag'],
                                    "Exploratory": notebook_config['exploratory_name'],
                                    "product": "datalab"}
+        notebook_config['custom_tag'] = ''
+        if 'custom_tag' in os.environ['tags']:
+            notebook_config['custom_tag'] = json.loads(os.environ['tags'].replace("'", '"'))['custom_tag']
+            if notebook_config['custom_tag']:
+                notebook_config['tags']['custom_tag'] = notebook_config['custom_tag']
         notebook_config['network_interface_name'] = notebook_config['instance_name'] + "-nif"
         notebook_config['security_group_name'] = '{}-{}-{}-nb-sg'.format(notebook_config['service_base_name'],
                                                                          notebook_config['project_name'],
diff --git a/infrastructure-provisioning/src/general/scripts/azure/common_stop_notebook.py b/infrastructure-provisioning/src/general/scripts/azure/common_stop_notebook.py
index 3154875..a147d47 100644
--- a/infrastructure-provisioning/src/general/scripts/azure/common_stop_notebook.py
+++ b/infrastructure-provisioning/src/general/scripts/azure/common_stop_notebook.py
@@ -31,6 +31,20 @@
 
 
 def stop_notebook(resource_group_name, notebook_name):
+    logging.info("Terminating Dataengine-service clusters")
+    try:
+        clusters_list = AzureMeta.list_hdinsight_clusters(resource_group_name)
+        if clusters_list:
+            for cluster in clusters_list:
+                if "notebook_name" in cluster.tags and notebook_name == cluster.tags["notebook_name"]:
+                    AzureActions.terminate_hdinsight_cluster(resource_group_name, cluster.name)
+                    logging.info('The HDinsight cluster {} has been terminated successfully'.format(cluster.name))
+        else:
+            logging.info("There are no HDinsight clusters to terminate.")
+    except Exception as err:
+        datalab.fab.append_result("Failed to terminate dataengine-service", str(err))
+        sys.exit(1)
+
     logging.info("Stopping data engine cluster")
     cluster_list = []
     try:
diff --git a/infrastructure-provisioning/src/general/scripts/azure/common_terminate_notebook.py b/infrastructure-provisioning/src/general/scripts/azure/common_terminate_notebook.py
index 77ef93f..7e30966 100644
--- a/infrastructure-provisioning/src/general/scripts/azure/common_terminate_notebook.py
+++ b/infrastructure-provisioning/src/general/scripts/azure/common_terminate_notebook.py
@@ -25,6 +25,7 @@
 import datalab.fab
 import datalab.meta_lib
 import json
+import requests
 from datalab.logger import logging
 import os
 import sys
@@ -32,6 +33,20 @@
 
 
 def terminate_nb(resource_group_name, notebook_name):
+    logging.info("Terminating Dataengine-service clusters")
+    try:
+        clusters_list = AzureMeta.list_hdinsight_clusters(resource_group_name)
+        if clusters_list:
+            for cluster in clusters_list:
+                if "notebook_name" in cluster.tags and notebook_name == cluster.tags["notebook_name"]:
+                    AzureActions.terminate_hdinsight_cluster(resource_group_name, cluster.name)
+                    logging.info('The HDinsight cluster {} has been terminated successfully'.format(cluster.name))
+        else:
+            logging.info("There are no HDinsight clusters to terminate.")
+    except Exception as err:
+        datalab.fab.append_result("Failed to terminate dataengine-service", str(err))
+        sys.exit(1)
+
     logging.info("Terminating data engine cluster")
     try:
         for vm in AzureMeta.compute_client.virtual_machines.list(resource_group_name):
@@ -54,6 +69,44 @@
         datalab.fab.append_result("Failed to terminate instance", str(err))
         sys.exit(1)
 
+    if os.environ['notebook_create_keycloak_client'] == 'True':
+        logging.info("Terminating notebook keycloak client")
+        try:
+            keycloak_auth_server_url = '{}/realms/master/protocol/openid-connect/token'.format(
+                os.environ['keycloak_auth_server_url'])
+            keycloak_client_url = '{0}/admin/realms/{1}/clients'.format(os.environ['keycloak_auth_server_url'],
+                                                                        os.environ['keycloak_realm_name'])
+
+            keycloak_auth_data = {
+                "username": os.environ['keycloak_user'],
+                "password": os.environ['keycloak_user_password'],
+                "grant_type": "password",
+                "client_id": "admin-cli",
+            }
+
+            client_params = {
+                "clientId": "{}-{}-{}-{}".format(notebook_config['service_base_name'], notebook_config['project_name'],
+                                                 notebook_config['endpoint_name'], notebook_config['exploratory_name'])
+            }
+
+            keycloak_token = requests.post(keycloak_auth_server_url, data=keycloak_auth_data).json()
+
+            keycloak_get_id_client = requests.get(keycloak_client_url, data=keycloak_auth_data, params=client_params,
+                                                  headers={"Authorization": "Bearer " + keycloak_token.get("access_token"),
+                                                           "Content-Type": "application/json"})
+            json_keycloak_client_id = json.loads(keycloak_get_id_client.text)
+            keycloak_id_client = json_keycloak_client_id[0]['id']
+
+            keycloak_client_delete_url = '{0}/admin/realms/{1}/clients/{2}'.format(os.environ['keycloak_auth_server_url'],
+                                                                                   os.environ['keycloak_realm_name'],
+                                                                                   keycloak_id_client)
+
+            requests.delete(keycloak_client_delete_url,
+                            headers={"Authorization": "Bearer " + keycloak_token.get("access_token"),
+                                     "Content-Type": "application/json"})
+        except Exception as err:
+            logging.error("Failed to remove project client from Keycloak", str(err))
+
 
 if __name__ == "__main__":
     # generating variables dictionary
diff --git a/infrastructure-provisioning/src/general/scripts/azure/common_terminate_notebook_image.py b/infrastructure-provisioning/src/general/scripts/azure/common_terminate_notebook_image.py
index 295ecab..06df201 100644
--- a/infrastructure-provisioning/src/general/scripts/azure/common_terminate_notebook_image.py
+++ b/infrastructure-provisioning/src/general/scripts/azure/common_terminate_notebook_image.py
@@ -35,17 +35,28 @@
         image_conf = dict()
         image_conf['service_base_name'] = os.environ['conf_service_base_name']
         image_conf['resource_group_name'] = os.environ['azure_resource_group_name']
-        image_conf['full_image_name'] = os.environ['notebook_image_name']
+        image_conf['project_name'] = os.environ['project_name']
+        image_conf['endpoint_name'] = os.environ['endpoint_name']
+        image_conf['application'] = os.environ['application']
+        image_conf['image_name'] = os.environ['notebook_image_name']
+        image_conf['full_image_name'] = '{}-{}-{}-{}-{}'.format(image_conf['service_base_name'],
+                                                                image_conf['project_name'],
+                                                                image_conf['endpoint_name'],
+                                                                image_conf['application'],
+                                                                image_conf['image_name'])
 
         image = AzureMeta.get_image(image_conf['resource_group_name'], image_conf['full_image_name'])
         if image != '':
             AzureActions.remove_image(image_conf['resource_group_name'], image_conf['full_image_name'])
 
-            with open("/root/result.json", 'w') as result:
-                res = {"notebook_image_name": image_conf['full_image_name'],
-                       "status": "terminated",
-                       "Action": "Delete existing notebook image"}
-                result.write(json.dumps(res))
+        with open("/root/result.json", 'w') as result:
+            res = {"notebook_image_name": image_conf['full_image_name'],
+                   "endpoint": image_conf['endpoint_name'],
+                   "project": image_conf['project_name'],
+                   "imageName": image_conf['image_name'],
+                   "status": "terminated",
+                   "Action": "Delete existing notebook image"}
+            result.write(json.dumps(res))
     except Exception as err:
         datalab.fab.append_result("Failed to delete existing notebook image", str(err))
         sys.exit(1)
diff --git a/infrastructure-provisioning/src/general/scripts/azure/dataengine-service_configure.py b/infrastructure-provisioning/src/general/scripts/azure/dataengine-service_configure.py
new file mode 100644
index 0000000..5ceb8c6
--- /dev/null
+++ b/infrastructure-provisioning/src/general/scripts/azure/dataengine-service_configure.py
@@ -0,0 +1,142 @@
+#!/usr/bin/python3
+
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+import datalab.actions_lib
+import datalab.fab
+import datalab.meta_lib
+import json
+from datalab.logger import logging
+import multiprocessing
+import os
+import sys
+import traceback
+import subprocess
+from Crypto.PublicKey import RSA
+from fabric import *
+import argparse
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--uuid', type=str, default='')
+parser.add_argument('--access_password', type=str, default='')
+args = parser.parse_args()
+
+
+def add_notebook_secret(resource_group_name, instance_name, os_user, keyfile, computational_name, cluster_password):
+    private_ip = AzureMeta.get_private_ip_address(resource_group_name, instance_name)
+    global conn
+    conn = datalab.fab.init_datalab_connection(private_ip, os_user, keyfile)
+    datalab.actions_lib.ensure_hdinsight_secret(os_user, computational_name, cluster_password)
+
+
+if __name__ == "__main__":
+    try:
+        AzureMeta = datalab.meta_lib.AzureMeta()
+        AzureActions = datalab.actions_lib.AzureActions()
+        logging.info('Generating infrastructure names and tags')
+        hdinsight_conf = dict()
+        hdinsight_conf['service_base_name'] = os.environ['conf_service_base_name']
+        hdinsight_conf['resource_group_name'] = os.environ['azure_resource_group_name']
+        hdinsight_conf['region'] = os.environ['azure_region']
+        hdinsight_conf['key_name'] = os.environ['conf_key_name']
+        hdinsight_conf['vpc_name'] = os.environ['azure_vpc_name']
+        hdinsight_conf['user_name'] = os.environ['edge_user_name']
+        hdinsight_conf['project_name'] = os.environ['project_name']
+        hdinsight_conf['project_tag'] = hdinsight_conf['project_name']
+        hdinsight_conf['endpoint_name'] = os.environ['endpoint_name']
+        hdinsight_conf['endpoint_tag'] = hdinsight_conf['endpoint_name']
+        hdinsight_conf['hdinsight_master_instance_type'] = os.environ['hdinsight_master_instance_type']
+        hdinsight_conf['hdinsight_slave_instance_type'] = os.environ['hdinsight_slave_instance_type']
+        hdinsight_conf['key_path'] = '{}/{}.pem'.format(os.environ['conf_key_dir'],
+                                                        os.environ['conf_key_name'])
+        if 'computational_name' in os.environ:
+            hdinsight_conf['computational_name'] = os.environ['computational_name'].lower().replace('_', '-')
+        else:
+            hdinsight_conf['computational_name'] = ''
+
+        hdinsight_conf['cluster_name'] = '{}-{}-{}-des-{}'.format(hdinsight_conf['service_base_name'],
+                                                                  hdinsight_conf['project_name'],
+                                                                  hdinsight_conf['endpoint_name'],
+                                                                  hdinsight_conf['computational_name'])
+
+        hdinsight_conf['full_cluster_name'] = '{}-{}-{}-{}-des-{}'.format(args.uuid, hdinsight_conf['service_base_name'],
+                                                                     hdinsight_conf['project_name'],
+                                                                     hdinsight_conf['endpoint_name'],
+                                                                     hdinsight_conf['computational_name'])
+        hdinsight_conf["instance_id"] = hdinsight_conf["full_cluster_name"]
+        hdinsight_conf['cluster_url'] = 'https://{}.azurehdinsight.net'.format(hdinsight_conf['full_cluster_name'])
+        hdinsight_conf['cluster_jupyter_url'] = '{}/jupyter/'.format(hdinsight_conf['cluster_url'])
+        hdinsight_conf['cluster_sparkhistory_url'] = '{}/sparkhistory/'.format(hdinsight_conf['cluster_url'])
+        hdinsight_conf['cluster_zeppelin_url'] = '{}/zeppelin/'.format(hdinsight_conf['cluster_url'])
+
+        if os.environ["application"] == "rstudio":
+            add_notebook_secret(hdinsight_conf['resource_group_name'], os.environ["notebook_instance_name"],
+                                os.environ["conf_os_user"], hdinsight_conf['key_path'],
+                                hdinsight_conf['computational_name'], args.access_password)
+            hdinsight_conf['rstudio_livy_connection'] = 'library(sparklyr); ' \
+                                                        'sc <- spark_connect(master = "{}/livy/", ' \
+                                                        'version = "3.1.1", method = "livy", ' \
+                                                        'config = livy_config(username = "{}", ' \
+                                                        'password = Sys.getenv("{}-access-password")))' \
+                .format(hdinsight_conf['cluster_url'], os.environ["conf_os_user"], hdinsight_conf['computational_name'])
+        else:
+            hdinsight_conf['rstudio_livy_connection'] = ''
+
+        logging.info('[SUMMARY]')
+        logging.info("Service base name: {}".format(hdinsight_conf['service_base_name']))
+        logging.info("Region: {}".format(hdinsight_conf['region']))
+        logging.info("Cluster name: {}".format(hdinsight_conf['full_cluster_name']))
+        logging.info("Master node shape: {}".format(hdinsight_conf['hdinsight_master_instance_type']))
+        logging.info("Slave node shape: {}".format(hdinsight_conf['hdinsight_slave_instance_type']))
+        logging.info("Instance count: {}".format(str(os.environ['hdinsight_count'])))
+        logging.info("URL access username: datalab-user")
+        logging.info("URL access password: {}".format(args.access_password))
+        logging.info("Cluster URL: {}".format(hdinsight_conf['cluster_url']))
+        logging.info("Spark History URL: {}".format(hdinsight_conf['cluster_sparkhistory_url']))
+        logging.info("Jupyter URL: {}".format(hdinsight_conf['cluster_jupyter_url']))
+        logging.info("Zeppelin URL: {}".format(hdinsight_conf['cluster_zeppelin_url']))
+
+        with open("/root/result.json", 'w') as result:
+            res = {"hostname": hdinsight_conf['full_cluster_name'],
+                   "key_name": hdinsight_conf['key_name'],
+                   "instance_id": hdinsight_conf["instance_id"],
+                   "Action": "Create new HDInsight cluster",
+                   "computational_url": [
+                       # {"description": "HDInsight cluster",
+                       #  "url": hdinsight_conf['cluster_url']},
+                       {"description": "Apache Spark History",
+                        "url": hdinsight_conf['cluster_sparkhistory_url']},
+                       {"description": "Connection string",
+                        "url": hdinsight_conf['rstudio_livy_connection']}
+                       # {"description": "Jupyter notebook",
+                       #  "url": hdinsight_conf['cluster_jupyter_url']},
+                       # {"description": "Zeppelin notebook",
+                       #  "url": hdinsight_conf['cluster_zeppelin_url']}
+                   ],
+                   }
+            result.write(json.dumps(res))
+    except Exception as err:
+        traceback.print_exc()
+        datalab.fab.append_result("Error with writing results", str(err))
+        AzureActions.terminate_hdinsight_cluster(hdinsight_conf['resource_group_name'],
+                                                 hdinsight_conf['full_cluster_name'])
+        sys.exit(1)
diff --git a/infrastructure-provisioning/src/general/scripts/azure/dataengine-service_create.py b/infrastructure-provisioning/src/general/scripts/azure/dataengine-service_create.py
new file mode 100644
index 0000000..b2e2c8b
--- /dev/null
+++ b/infrastructure-provisioning/src/general/scripts/azure/dataengine-service_create.py
@@ -0,0 +1,201 @@
+#!/usr/bin/python3
+
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+import argparse
+import json
+import sys
+import os
+from datalab.actions_lib import *
+from datalab.meta_lib import *
+from datalab.logger import logging
+from fabric import *
+from azure.mgmt.hdinsight.models import *
+from azure.mgmt.core import *
+from azure.common import *
+from azure.core import *
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--resource_group_name', type=str, help='')
+parser.add_argument('--cluster_name', type=str, help='')
+parser.add_argument('--cluster_version', type=str, help='')
+parser.add_argument('--location', type=str, help='')
+parser.add_argument('--master_instance_type', type=str, help='')
+parser.add_argument('--worker_instance_type', type=str, help='')
+parser.add_argument('--worker_count', type=str, help='')
+parser.add_argument('--cluster_storage_account_name', type=str, help='')
+parser.add_argument('--cluster_storage_account_key', type=str, help='')
+parser.add_argument('--cluster_container_name', type=str, help='')
+parser.add_argument('--edge_storage_account_name', type=str, help='')
+parser.add_argument('--edge_storage_account_key', type=str, help='')
+parser.add_argument('--edge_container_name', type=str, help='')
+parser.add_argument('--shared_storage_account_name', type=str, help='')
+parser.add_argument('--shared_storage_account_key', type=str, help='')
+parser.add_argument('--shared_container_name', type=str, help='')
+parser.add_argument('--tags', type=str, help='')
+parser.add_argument('--public_key', type=str, help='')
+parser.add_argument('--vpc_id', type=str, help='')
+parser.add_argument('--subnet', type=str, help='')
+parser.add_argument('--access_password', type=str, help='')
+args = parser.parse_args()
+
+
+def build_hdinsight_cluster(resource_group_name, cluster_name, params):
+    logging.info("{} cluster creation".format(cluster_name))
+    return datalab.actions_lib.AzureActions().create_hdinsight_cluster(resource_group_name, cluster_name, params)
+
+
+def create_cluster_parameters(location, tags, cluster_version, cluster_login_username, password, master_instance_type,
+                              worker_count, worker_instance_type, cluster_storage_account_name, cluster_storage_account_key,
+                              cluster_container_name, public_key, vpc_id, subnet,
+                              edge_storage_account_name, edge_storage_account_key, edge_container_name,
+                              shared_storage_account_name, shared_storage_account_key, shared_container_name):
+
+    # Returns cluster parameters
+
+    return ClusterCreateParametersExtended(
+        location=location,
+        tags=tags,
+        properties=ClusterCreateProperties(
+            cluster_version=cluster_version,
+            os_type=OSType.linux,
+            tier=Tier.standard,
+            cluster_definition=ClusterDefinition(
+                kind="Spark",
+                component_version=
+                {
+                    "Spark": "3.1"
+                },
+                configurations={
+                    "gateway": {
+                        "restAuthCredential.isEnabled": "true",
+                        "restAuthCredential.username": cluster_login_username,
+                        "restAuthCredential.password": password
+                    }
+                }
+            ),
+            compute_profile=ComputeProfile(
+                roles=[
+                    Role(
+                        name="headnode",
+                        target_instance_count=2,
+                        hardware_profile=HardwareProfile(vm_size=master_instance_type),
+                        os_profile=OsProfile(
+                            linux_operating_system_profile=LinuxOperatingSystemProfile(
+                                username=cluster_login_username,
+                                ssh_profile={
+                                    "publicKeys": [
+                                        {"certificateData": public_key}
+                                    ]
+                                }
+                            )
+                        ),
+                        virtual_network_profile=VirtualNetworkProfile(
+                            id=vpc_id,
+                            subnet=subnet
+                        )
+                    ),
+                    Role(
+                        name="workernode",
+                        target_instance_count=int(worker_count),
+                        hardware_profile=HardwareProfile(vm_size=worker_instance_type),
+                        os_profile=OsProfile(
+                            linux_operating_system_profile=LinuxOperatingSystemProfile(
+                                username=cluster_login_username,
+                                ssh_profile={
+                                    "publicKeys": [
+                                        {"certificateData": public_key}
+                                    ]
+                                }
+                            )
+                        ),
+                        virtual_network_profile=VirtualNetworkProfile(
+                            id=vpc_id,
+                            subnet=subnet
+                        )
+                    ),
+                    Role(
+                        name="zookeepernode",
+                        target_instance_count=3,
+                        hardware_profile=HardwareProfile(vm_size="Standard_A2_v2"),
+                        os_profile=OsProfile(
+                            linux_operating_system_profile=LinuxOperatingSystemProfile(
+                                username=cluster_login_username,
+                                ssh_profile={
+                                    "publicKeys": [
+                                        {"certificateData": public_key}
+                                    ]
+                                }
+                            )
+                        ),
+                        virtual_network_profile=VirtualNetworkProfile(
+                            id=vpc_id,
+                            subnet=subnet
+                        )
+                    )
+                ]
+            ),
+            storage_profile=StorageProfile(
+                storageaccounts=[
+                    StorageAccount(
+                        name=cluster_storage_account_name + ".blob.core.windows.net",
+                        key=cluster_storage_account_key,
+                        container=cluster_container_name.lower(),
+                        is_default=True
+                    ),
+                    StorageAccount(
+                        name=edge_storage_account_name + ".blob.core.windows.net",
+                        key=edge_storage_account_key,
+                        container=edge_container_name.lower()
+                    ),
+                    StorageAccount(
+                        name=shared_storage_account_name + ".blob.core.windows.net",
+                        key=shared_storage_account_key,
+                        container=shared_container_name.lower()
+                    )
+                ]
+            )
+        )
+    )
+
+##############
+# Run script #
+##############
+
+if __name__ == "__main__":
+    #parser.print_help()
+    params = create_cluster_parameters(args.location, json.loads(args.tags), args.cluster_version, 'datalab-user',
+                                       args.access_password, args.master_instance_type, args.worker_count,
+                                       args.worker_instance_type, args.cluster_storage_account_name, args.cluster_storage_account_key,
+                                       args.cluster_container_name, args.public_key, args.vpc_id, args.subnet,
+                                       args.edge_storage_account_name, args.edge_storage_account_key,
+                                       args.edge_container_name, args.shared_storage_account_name,
+                                       args.shared_storage_account_key, args.shared_container_name)
+
+    build_hdinsight_cluster(args.resource_group_name, args.cluster_name, params)
+
+    # logfile = '{}_creation.log'.format(args.cluster_name)
+    # logpath = '/response/' + logfile
+    # out = open(logpath, 'w')
+    # out.close()
+    #
+    # sys.exit(0)
diff --git a/infrastructure-provisioning/src/general/scripts/azure/dataengine-service_prepare.py b/infrastructure-provisioning/src/general/scripts/azure/dataengine-service_prepare.py
new file mode 100644
index 0000000..112d2d5
--- /dev/null
+++ b/infrastructure-provisioning/src/general/scripts/azure/dataengine-service_prepare.py
@@ -0,0 +1,203 @@
+#!/usr/bin/python3
+
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+import datalab.fab
+import datalab.meta_lib
+import datalab.actions_lib
+import json
+import multiprocessing
+import os
+import sys
+import traceback
+import subprocess
+from Crypto.PublicKey import RSA
+from datalab.logger import logging
+from fabric import *
+import argparse
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--uuid', type=str, default='')
+parser.add_argument('--access_password', type=str, default='')
+args = parser.parse_args()
+
+if __name__ == "__main__":
+    try:
+        AzureActions = datalab.actions_lib.AzureActions()
+        AzureMeta = datalab.meta_lib.AzureMeta()
+        logging.info('Generating infrastructure names and tags')
+        hdinsight_conf = dict()
+        if 'exploratory_name' in os.environ:
+            hdinsight_conf['exploratory_name'] = os.environ['exploratory_name'].replace('_', '-').lower()
+        else:
+            hdinsight_conf['exploratory_name'] = ''
+        if 'computational_name' in os.environ:
+            hdinsight_conf['computational_name'] = os.environ['computational_name'].replace('_', '-').lower()
+        else:
+            hdinsight_conf['computational_name'] = ''
+        hdinsight_conf['hdinsight_worker_count'] = int(os.environ['hdinsight_count']) - 2
+        hdinsight_conf['service_base_name'] = (os.environ['conf_service_base_name'])
+        hdinsight_conf['project_name'] = (os.environ['project_name']).replace('_', '-').lower()
+        hdinsight_conf['endpoint_name'] = (os.environ['endpoint_name']).replace('_', '-').lower()
+        hdinsight_conf['key_name'] = os.environ['conf_key_name']
+        hdinsight_conf['key_path'] = '{0}{1}.pem'.format(os.environ['conf_key_dir'], os.environ['conf_key_name'])
+        hdinsight_conf['resource_group_name'] = os.environ['azure_resource_group_name']
+        hdinsight_conf['region'] = os.environ['azure_region']
+        hdinsight_conf['tag_name'] = hdinsight_conf['service_base_name'] + '-tag'
+        hdinsight_conf['cluster_name'] = '{}-{}-{}-des-{}'.format(hdinsight_conf['service_base_name'],
+                                                                  hdinsight_conf['project_name'],
+                                                                  hdinsight_conf['endpoint_name'],
+                                                                  hdinsight_conf['computational_name'])
+        hdinsight_conf['full_cluster_name'] = '{}-{}-{}-{}-des-{}'.format(args.uuid,
+                                                                          hdinsight_conf['service_base_name'],
+                                                                          hdinsight_conf['project_name'],
+                                                                          hdinsight_conf['endpoint_name'],
+                                                                          hdinsight_conf['computational_name'])
+
+        hdinsight_conf['cluster_tags'] = {
+            "Name": hdinsight_conf['cluster_name'],
+            "SBN": hdinsight_conf['service_base_name'],
+            "notebook_name": os.environ['notebook_instance_name'],
+            "product": "datalab",
+            "computational_name": hdinsight_conf['computational_name'],
+            "project_tag": hdinsight_conf['project_name'],
+            "endpoint_tag": hdinsight_conf['endpoint_name']
+        }
+
+        hdinsight_conf['custom_tag'] = ''
+        if 'custom_tag' in os.environ['tags']:
+            hdinsight_conf['custom_tag'] = json.loads(os.environ['tags'].replace("'", '"'))['custom_tag']
+        if hdinsight_conf['custom_tag']:
+            hdinsight_conf['cluster_tags']['custom_tag'] = hdinsight_conf['custom_tag']
+
+        hdinsight_conf['release_label'] = os.environ['hdinsight_version']
+        key = RSA.importKey(open(hdinsight_conf['key_path'], 'rb').read())
+        ssh_admin_pubkey = key.publickey().exportKey("OpenSSH").decode('UTF-8')
+        hdinsight_conf['cluster_container_name'] = ('{}-bucket'.format(hdinsight_conf['cluster_name'])).lower()
+        hdinsight_conf['cluster_storage_account_name_tag'] = ('{}-bucket'.format(hdinsight_conf['cluster_name'])).lower()
+        hdinsight_conf['cluster_storage_account_tags'] = {"Name": hdinsight_conf['cluster_storage_account_name_tag'],
+                                                  "SBN": hdinsight_conf['service_base_name'],
+                                                  "project_tag": hdinsight_conf['project_name'],
+                                                  "endpoint_tag": hdinsight_conf['endpoint_name'],
+                                                  os.environ['conf_billing_tag_key']: os.environ['conf_billing_tag_value'],
+                                                  hdinsight_conf['tag_name']: hdinsight_conf['cluster_storage_account_name_tag']}
+
+        hdinsight_conf['edge_storage_account_name'] = ('{0}-{1}-{2}-bucket'.format(hdinsight_conf['service_base_name'],
+                                                                                   hdinsight_conf['project_name'],
+                                                                                   hdinsight_conf['endpoint_name'])).lower()
+        hdinsight_conf['edge_container_name'] = ('{0}-{1}-{2}-bucket'.format(hdinsight_conf['service_base_name'],
+                                                                             hdinsight_conf['project_name'],
+                                                                             hdinsight_conf['endpoint_name'])).lower()
+        hdinsight_conf['edge_storage_account_name_tag'] = hdinsight_conf['edge_storage_account_name']
+
+        hdinsight_conf['shared_storage_account_name'] = ('{0}-{1}-shared-bucket'.format(
+            hdinsight_conf['service_base_name'], hdinsight_conf['endpoint_name'])).lower()
+        hdinsight_conf['shared_container_name'] = ('{}-{}-shared-bucket'.format(hdinsight_conf['service_base_name'],
+                                                                                hdinsight_conf['endpoint_name'])).lower()
+        hdinsight_conf['shared_storage_account_name_tag'] = hdinsight_conf['shared_storage_account_name']
+
+        hdinsight_conf['vpc_name'] = os.environ['azure_vpc_name']
+
+        hdinsight_conf['vpc_id'] = AzureMeta.get_vpc(hdinsight_conf['resource_group_name'],
+                                                     hdinsight_conf['vpc_name']).id
+
+        hdinsight_conf['subnet_name'] = '{}-{}-{}-subnet'.format(hdinsight_conf['service_base_name'],
+                                                                 hdinsight_conf['project_name'],
+                                                                 hdinsight_conf['endpoint_name'])
+
+        hdinsight_conf['edge_network_id'] = AzureMeta.get_subnet(hdinsight_conf['resource_group_name'],
+                                                                 hdinsight_conf['vpc_name'],
+                                                                 hdinsight_conf['subnet_name']).id
+
+        hdinsight_conf['hdinsight_master_instance_type'] = os.environ['hdinsight_master_instance_type']
+        hdinsight_conf['hdinsight_slave_instance_type'] = os.environ['hdinsight_slave_instance_type']
+
+    except Exception as err:
+        datalab.fab.append_result("Failed to generate variables dictionary. Exception:" + str(err))
+        sys.exit(1)
+
+    try:
+        logging.info('[CREATE STORAGE ACCOUNT AND CONTAINERS]')
+
+        params = "--container_name {} --account_tags '{}' --resource_group_name {} --region {} " \
+                 "--storage_account_kind StorageV2". \
+            format(hdinsight_conf['cluster_container_name'], json.dumps(hdinsight_conf['cluster_storage_account_tags']),
+                   hdinsight_conf['resource_group_name'], hdinsight_conf['region'])
+        try:
+            subprocess.run("~/scripts/{}.py {}".format('common_create_storage_account', params), shell=True, check=True)
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        datalab.fab.append_result("Failed to create storage account.", str(err))
+        for storage_account in AzureMeta.list_storage_accounts(hdinsight_conf['resource_group_name']):
+            if hdinsight_conf['cluster_storage_account_name_tag'] == storage_account.tags["Name"]:
+                AzureActions.remove_storage_account(hdinsight_conf['resource_group_name'], storage_account.name)
+        sys.exit(1)
+
+    try:
+        logging.info('[Creating HDInsight Cluster]')
+        for storage_account in AzureMeta.list_storage_accounts(hdinsight_conf['resource_group_name']):
+            if hdinsight_conf['cluster_storage_account_name_tag'] == storage_account.tags["Name"]:
+                hdinsight_conf['cluster_storage_account_name'] = storage_account.name
+            if hdinsight_conf['edge_storage_account_name_tag'] == storage_account.tags["Name"]:
+                hdinsight_conf['edge_storage_account_name'] = storage_account.name
+            if hdinsight_conf['shared_storage_account_name_tag'] == storage_account.tags["Name"]:
+                hdinsight_conf['shared_storage_account_name'] = storage_account.name
+        hdinsight_conf['cluster_storage_account_key'] = AzureMeta.list_storage_keys(
+            hdinsight_conf['resource_group_name'], hdinsight_conf['cluster_storage_account_name'])[0]
+        hdinsight_conf['edge_storage_account_key'] = AzureMeta.list_storage_keys(
+            hdinsight_conf['resource_group_name'], hdinsight_conf['edge_storage_account_name'])[0]
+        hdinsight_conf['shared_storage_account_key'] = AzureMeta.list_storage_keys(
+            hdinsight_conf['resource_group_name'], hdinsight_conf['shared_storage_account_name'])[0]
+        params = "--resource_group_name {} --cluster_name {} " \
+                 "--cluster_version {} --location {} " \
+                 "--master_instance_type {} --worker_instance_type {} " \
+                 "--worker_count {} --cluster_storage_account_name {} " \
+                 "--cluster_storage_account_key '{}' --cluster_container_name {} " \
+                 "--tags '{}' --public_key '{}' --vpc_id {} --subnet {} --access_password {} " \
+                 "--edge_storage_account_name {} --edge_storage_account_key '{}' --edge_container_name {} " \
+                 "--shared_storage_account_name {} --shared_storage_account_key '{}' --shared_container_name {}"\
+            .format(hdinsight_conf['resource_group_name'], hdinsight_conf['full_cluster_name'],
+                    hdinsight_conf['release_label'], hdinsight_conf['region'],
+                    hdinsight_conf['hdinsight_master_instance_type'], hdinsight_conf['hdinsight_slave_instance_type'],
+                    hdinsight_conf['hdinsight_worker_count'], hdinsight_conf['cluster_storage_account_name'],
+                    hdinsight_conf['cluster_storage_account_key'], hdinsight_conf['cluster_container_name'],
+                    json.dumps(hdinsight_conf['cluster_tags']), ssh_admin_pubkey, hdinsight_conf['vpc_id'],
+                    hdinsight_conf['edge_network_id'], args.access_password,
+                    hdinsight_conf['edge_storage_account_name'], hdinsight_conf['edge_storage_account_key'],
+                    hdinsight_conf['edge_container_name'],  hdinsight_conf['shared_storage_account_name'],
+                    hdinsight_conf['shared_storage_account_key'], hdinsight_conf['shared_container_name'])
+
+        try:
+            subprocess.run("~/scripts/{}.py {}".format('dataengine-service_create', params), shell=True, check=True)
+        except:
+            traceback.print_exc()
+            raise Exception
+
+    except Exception as err:
+        datalab.fab.append_result("Failed to create hdinsight Cluster.", str(err))
+        for storage_account in AzureMeta.list_storage_accounts(hdinsight_conf['resource_group_name']):
+            if hdinsight_conf['cluster_storage_account_name_tag'] == storage_account.tags["Name"]:
+                AzureActions.remove_storage_account(hdinsight_conf['resource_group_name'], storage_account.name)
+        #subprocess.run('rm /response/.hdinsight_creating_{}'.format(os.environ['exploratory_name']), shell=True, check=True)
+        sys.exit(1)
diff --git a/infrastructure-provisioning/src/general/scripts/azure/dataengine-service_terminate.py b/infrastructure-provisioning/src/general/scripts/azure/dataengine-service_terminate.py
new file mode 100644
index 0000000..bbfddf4
--- /dev/null
+++ b/infrastructure-provisioning/src/general/scripts/azure/dataengine-service_terminate.py
@@ -0,0 +1,105 @@
+#!/usr/bin/python3
+
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+import datalab.actions_lib
+import datalab.fab
+import datalab.meta_lib
+import json
+import os
+import sys
+import traceback
+from datalab.logger import logging
+
+
+if __name__ == "__main__":
+    try:
+        # generating variables dictionary
+        logging.info('Generating infrastructure names and tags')
+        hdinsight_conf = dict()
+        AzureActions = datalab.actions_lib.AzureActions()
+        AzureMeta = datalab.meta_lib.AzureMeta()
+        if 'exploratory_name' in os.environ:
+            hdinsight_conf['exploratory_name'] = os.environ['exploratory_name'].replace('_', '-').lower()
+        else:
+            hdinsight_conf['exploratory_name'] = ''
+        if 'computational_name' in os.environ:
+            hdinsight_conf['computational_name'] = os.environ['computational_name'].replace('_', '-').lower()
+        else:
+            hdinsight_conf['computational_name'] = ''
+        hdinsight_conf['service_base_name'] = (os.environ['conf_service_base_name'])
+        hdinsight_conf['project_name'] = (os.environ['project_name']).replace('_', '-').lower()
+        hdinsight_conf['endpoint_name'] = (os.environ['endpoint_name']).replace('_', '-').lower()
+        hdinsight_conf['resource_group_name'] = os.environ['azure_resource_group_name']
+        hdinsight_conf['region'] = os.environ['azure_region']
+        hdinsight_conf['cluster_name'] = '{}-{}-{}-des-{}'.format(hdinsight_conf['service_base_name'],
+                                                                  hdinsight_conf['project_name'],
+                                                                  hdinsight_conf['endpoint_name'],
+                                                                  hdinsight_conf['computational_name'])
+        hdinsight_conf['storage_account_name_tag'] = ('{}-bucket'.format(hdinsight_conf['cluster_name'])).lower()
+        hdinsight_conf['container_name'] = ('{}-bucket'.format(hdinsight_conf['cluster_name'])).lower()
+        hdinsight_conf['key_path'] = os.environ['conf_key_dir'] + '/' + os.environ['conf_key_name'] + '.pem'
+        hdinsight_conf['notebook_instance_name'] = os.environ['notebook_instance_name']
+    except Exception as err:
+        datalab.fab.append_result("Failed to generate variables dictionary. Exception:" + str(err))
+        sys.exit(1)
+
+    try:
+        logging.info('[TERMINATE HDINSIGHT CLUSTER AND ASSOCIATED RESOURCES]')
+        try:
+            for cluster in AzureMeta.list_hdinsight_clusters(hdinsight_conf['resource_group_name']):
+                if hdinsight_conf['cluster_name'] == cluster.tags["Name"]:
+                    hdinsight_conf['full_cluster_name'] = cluster.name
+            cluster = AzureMeta.get_hdinsight_cluster(hdinsight_conf['resource_group_name'],
+                                                      hdinsight_conf['full_cluster_name'])
+            if cluster and cluster.properties.cluster_state == 'Running':
+                AzureActions.terminate_hdinsight_cluster(hdinsight_conf['resource_group_name'],
+                                                         hdinsight_conf['full_cluster_name'])
+            for storage_account in AzureMeta.list_storage_accounts(hdinsight_conf['resource_group_name']):
+                if hdinsight_conf['storage_account_name_tag'] == storage_account.tags["Name"]:
+                    AzureActions.remove_storage_account(hdinsight_conf['resource_group_name'], storage_account.name)
+        except Exception as err:
+            traceback.print_exc()
+            datalab.fab.append_result("Failed to terminate hdinsight cluster.", str(err))
+            raise Exception
+    except:
+        sys.exit(1)
+
+    logging.info("[REMOVING NOTEBOOK KERNELS]")
+    try:
+        AzureActions.remove_dataengine_kernels(hdinsight_conf['resource_group_name'],
+                                               hdinsight_conf['notebook_instance_name'], os.environ['conf_os_user'],
+                                               hdinsight_conf['key_path'], hdinsight_conf['cluster_name'])
+    except Exception as err:
+        datalab.fab.append_result("Failed to remove dataengine kernels from notebook", str(err))
+        sys.exit(1)
+
+    try:
+        with open("/root/result.json", 'w') as result:
+            res = {"dataengine-service_name": hdinsight_conf['computational_name'],
+                   "notebook_name": hdinsight_conf['notebook_instance_name'],
+                   "Action": "Terminate HDInsight cluster"}
+            print(json.dumps(res))
+            result.write(json.dumps(res))
+    except Exception as err:
+        datalab.fab.append_result("Error with writing results", str(err))
+        sys.exit(1)
diff --git a/infrastructure-provisioning/src/general/scripts/azure/dataengine_prepare.py b/infrastructure-provisioning/src/general/scripts/azure/dataengine_prepare.py
index 58cd95b..265a635 100644
--- a/infrastructure-provisioning/src/general/scripts/azure/dataengine_prepare.py
+++ b/infrastructure-provisioning/src/general/scripts/azure/dataengine_prepare.py
@@ -98,6 +98,12 @@
                                       "Type": "master",
                                       "notebook_name": data_engine['notebook_name'],
                                       os.environ['conf_billing_tag_key']: os.environ['conf_billing_tag_value']}
+        data_engine['custom_tag'] = ''
+        if 'custom_tag' in os.environ['tags']:
+            data_engine['custom_tag'] = json.loads(os.environ['tags'].replace("'", '"'))['custom_tag']
+        if data_engine['custom_tag']:
+            data_engine['slave_tags']['custom_tag'] = data_engine['custom_tag']
+            data_engine['master_tags']['custom_tag'] = data_engine['custom_tag']
         # data_engine['primary_disk_size'] = '32'
         if os.environ['conf_deeplearning_cloud_ami'] == 'true' and os.environ['application'] == 'deeplearning':
             data_engine['primary_disk_size'] = '150'
diff --git a/infrastructure-provisioning/src/general/scripts/azure/edge_prepare.py b/infrastructure-provisioning/src/general/scripts/azure/edge_prepare.py
index 1e94746..ba444cf 100644
--- a/infrastructure-provisioning/src/general/scripts/azure/edge_prepare.py
+++ b/infrastructure-provisioning/src/general/scripts/azure/edge_prepare.py
@@ -690,14 +690,14 @@
             for storage_account in AzureMeta().list_storage_accounts(edge_conf['resource_group_name']):
                 if edge_conf['edge_storage_account_name'] == storage_account.tags["Name"]:
                     AzureActions().remove_storage_account(edge_conf['resource_group_name'], storage_account.name)
-            try:
-                for datalake in AzureMeta().list_datalakes(edge_conf['resource_group_name']):
-                    if edge_conf['datalake_store_name'] == datalake.tags["Name"]:
-                        AzureActions().remove_datalake_directory(datalake.name, edge_conf['datalake_user_directory_name'])
-            except Exception as err:
-                logging.info('Error: {0}'.format(err))
-                logging.info("Data Lake Store directory hasn't been created.")
-            sys.exit(1)
+           # try:
+           #     for datalake in AzureMeta().list_datalakes(edge_conf['resource_group_name']):
+           #         if edge_conf['datalake_store_name'] == datalake.tags["Name"]:
+           #             AzureActions().remove_datalake_directory(datalake.name, edge_conf['datalake_user_directory_name'])
+           # except Exception as err:
+           #     logging.info('Error: {0}'.format(err))
+           #     logging.info("Data Lake Store directory hasn't been created.")
+           # sys.exit(1)
 
     if os.environ['conf_os_family'] == 'debian':
         initial_user = 'ubuntu'
diff --git a/infrastructure-provisioning/src/general/scripts/azure/edge_terminate.py b/infrastructure-provisioning/src/general/scripts/azure/edge_terminate.py
index fc317d9..e0ff79e 100644
--- a/infrastructure-provisioning/src/general/scripts/azure/edge_terminate.py
+++ b/infrastructure-provisioning/src/general/scripts/azure/edge_terminate.py
@@ -97,18 +97,18 @@
         datalab.fab.append_result("Failed to remove storage accounts", str(err))
         sys.exit(1)
 
-    logging.info("Deleting Data Lake Store directory")
-    try:
-        for datalake in AzureMeta.list_datalakes(resource_group_name):
-            try:
-                if service_base_name == datalake.tags["SBN"]:
-                    AzureActions.remove_datalake_directory(datalake.name, project_tag + '-folder')
-                    logging.info("Data Lake Store directory {} has been deleted".format(project_tag + '-folder'))
-            except:
-                pass
-    except Exception as err:
-        datalab.fab.append_result("Failed to remove Data Lake", str(err))
-        sys.exit(1)
+   # logging.info("Deleting Data Lake Store directory")
+   # try:
+   #     for datalake in AzureMeta.list_datalakes(resource_group_name):
+   #         try:
+   #             if service_base_name == datalake.tags["SBN"]:
+   #                 AzureActions.remove_datalake_directory(datalake.name, project_tag + '-folder')
+   #                 logging.info("Data Lake Store directory {} has been deleted".format(project_tag + '-folder'))
+   #         except:
+   #             pass
+   # except Exception as err:
+   #     datalab.fab.append_result("Failed to remove Data Lake", str(err))
+   #     sys.exit(1)
 
     logging.info("Removing security groups")
     try:
diff --git a/infrastructure-provisioning/src/general/scripts/azure/jupyter_configure.py b/infrastructure-provisioning/src/general/scripts/azure/jupyter_configure.py
index 6f42803..3411fa8 100644
--- a/infrastructure-provisioning/src/general/scripts/azure/jupyter_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/azure/jupyter_configure.py
@@ -31,6 +31,7 @@
 import traceback
 import subprocess
 from fabric import *
+import uuid
 
 if __name__ == "__main__":
     try:
@@ -288,6 +289,44 @@
             AzureActions.remove_instance(notebook_config['resource_group_name'], notebook_config['instance_name'])
             sys.exit(1)
 
+    if os.environ['notebook_create_keycloak_client'] == 'True':
+        try:
+            logging.info('[SETUP KEYCLOAK CLIENT]')
+            notebook_config['keycloak_client_name'] = '{}-{}-{}-{}'\
+                .format(notebook_config['service_base_name'], notebook_config['project_name'],
+                        notebook_config['endpoint_name'], notebook_config['exploratory_name'])
+            notebook_config['keycloak_client_secret'] = str(uuid.uuid4())
+            keycloak_params = "--service_base_name {} --keycloak_auth_server_url {} --keycloak_realm_name {} " \
+                              "--keycloak_user {} --keycloak_user_password {} --keycloak_client_secret {} " \
+                              "--project_name {} --endpoint_name {} --exploratory_name {}"\
+                .format(notebook_config['service_base_name'], os.environ['keycloak_auth_server_url'],
+                        os.environ['keycloak_realm_name'], os.environ['keycloak_user'],
+                        os.environ['keycloak_user_password'], notebook_config['keycloak_client_secret'],
+                        notebook_config['project_name'], notebook_config['endpoint_name'],
+                        notebook_config['exploratory_name'])
+            try:
+                subprocess.run("~/scripts/{}.py {}".format('configure_keycloak', keycloak_params), shell=True, check=True)
+            except:
+                datalab.fab.append_result("Failed setup keycloak client")
+                raise Exception
+
+            try:
+                conn = datalab.fab.init_datalab_connection(instance_hostname, notebook_config['datalab_ssh_user'],
+                                                           notebook_config['ssh_key_path'], '', False)
+                content = json.loads(conn.sudo("cat /home/{}/.local/share/jupyter/kernels/py3spark_local/kernel.json"
+                                               .format(notebook_config['datalab_ssh_user'])).stdout)
+                content['env']['KEYCLOAK_CLIENT'] = notebook_config['keycloak_client_name']
+                content['env']['KEYCLOAK_SECRET'] = notebook_config['keycloak_client_secret']
+                conn.sudo("echo '{}' > /home/{}/.local/share/jupyter/kernels/py3spark_local/kernel.json"
+                          .format(json.dumps(content), notebook_config['datalab_ssh_user']))
+                conn.sudo('systemctl restart jupyter-notebook')
+            except:
+                datalab.fab.append_result("Failed to write variables to .bashrc")
+                raise Exception
+
+        except Exception as err:
+            datalab.fab.append_result("Failed setup keycloak client ", str(err))
+
     try:
         logging.info('[SETUP EDGE REVERSE PROXY TEMPLATE]')
         additional_info = {
diff --git a/infrastructure-provisioning/src/general/scripts/azure/jupyter_dataengine-service_create_configs.py b/infrastructure-provisioning/src/general/scripts/azure/jupyter_dataengine-service_create_configs.py
new file mode 100644
index 0000000..40b4684
--- /dev/null
+++ b/infrastructure-provisioning/src/general/scripts/azure/jupyter_dataengine-service_create_configs.py
@@ -0,0 +1,89 @@
+#!/usr/bin/python3
+
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+import argparse
+import sys
+import subprocess
+from datalab.actions_lib import *
+from datalab.common_lib import *
+from datalab.fab import *
+from datalab.notebook_lib import *
+from fabric import *
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--bucket', type=str, default='')
+parser.add_argument('--cluster_name', type=str, default='')
+parser.add_argument('--dry_run', type=str, default='false')
+parser.add_argument('--hdinsight_version', type=str, default='')
+parser.add_argument('--dataproc_version', type=str, default='')
+parser.add_argument('--spark_version', type=str, default='')
+parser.add_argument('--hadoop_version', type=str, default='')
+parser.add_argument('--region', type=str, default='')
+parser.add_argument('--user_name', type=str, default='')
+parser.add_argument('--os_user', type=str, default='')
+parser.add_argument('--pip_mirror', type=str, default='')
+parser.add_argument('--application', type=str, default='')
+parser.add_argument('--scala_version', type=str, default='')
+parser.add_argument('--python_version', type=str, default='')
+parser.add_argument('--headnode_ip', type=str, default='')
+args = parser.parse_args()
+
+hdinsight_dir = '/opt/{}/jars/'.format(args.hdinsight_version)
+kernels_dir = '/home/{}/.local/share/jupyter/kernels/'.format(args.os_user)
+spark_dir = '/opt/{}/{}/spark/'.format(args.hdinsight_version, args.cluster_name)
+yarn_dir = '/opt/{}/{}/conf/'.format(args.hdinsight_version, args.cluster_name)
+
+
+def install_sparkamagic_kernels(args):
+    try:
+        subprocess.run('sudo jupyter nbextension enable --py --sys-prefix widgetsnbextension')
+        sparkmagic_dir = subprocess.run("sudo pip3 show sparkmagic | grep 'Location: ' | awk '{print $2}'", capture_output=True, shell=True, check=True).stdout.decode('UTF-8').rstrip("\n\r")
+        subprocess.run('sudo jupyter-kernelspec install {}/sparkmagic/kernels/sparkkernel --prefix=/home/{}/.local/'.format(sparkmagic_dir, args.os_user), shell=True, check=True)
+        subprocess.run('sudo jupyter-kernelspec install {}/sparkmagic/kernels/pysparkkernel --prefix=/home/{}/.local/'.format(sparkmagic_dir, args.os_user), shell=True, check=True)
+        #subprocess.run('sudo jupyter-kernelspec install {}/sparkmagic/kernels/sparkrkernel --prefix=/home/{}/.local/'.format(sparkmagic_dir, args.os_user), shell=True, check=True)
+        pyspark_kernel_name = 'PySpark (Python-{0} / Spark-{1} ) [{2}]'.format(args.python_version, args.spark_version,
+                                                                         args.cluster_name)
+        subprocess.run('sed -i \'s|PySpark|{0}|g\' /home/{1}/.local/share/jupyter/kernels/pysparkkernel/kernel.json'.format(
+            pyspark_kernel_name, args.os_user), shell=True, check=True)
+        spark_kernel_name = 'Spark (Scala-{0} / Spark-{1} ) [{2}]'.format(args.scala_version, args.spark_version,
+                                                                         args.cluster_name)
+        subprocess.run('sed -i \'s|Spark|{0}|g\' /home/{1}/.local/share/jupyter/kernels/sparkkernel/kernel.json'.format(
+            spark_kernel_name, args.os_user), shell=True, check=True)
+        #sparkr_kernel_name = 'SparkR (R-{0} / Spark-{1} ) [{2}]'.format(args.r_version, args.spark_version,
+        #                                                                    args.cluster_name)
+        #subprocess.run('sed -i \'s|SparkR|{0}|g\' /home/{1}/.local/share/jupyter/kernels/sparkrkernel/kernel.json'.format(
+        #    sparkr_kernel_name, args.os_user), shell=True, check=True)
+        subprocess.run('mkdir -p /home/' + args.os_user + '/.sparkmagic', shell=True, check=True)
+        subprocess.run('cp -f /tmp/dataengine-service_sparkmagic_config.json /home/' + args.os_user + '/.sparkmagic/config.json', shell=True, check=True)
+        subprocess.run('sed -i \'s|HEADNODEIP:PORT|{0}:{2}|g\' /home/{1}/.sparkmagic/config.json'.format(
+                args.master_ip, args.os_user, args.livy_port, shell=True, check=True)
+        subprocess.run('sudo chown -R {0}:{0} /home/{0}/.sparkmagic/'.format(args.os_user), shell=True, check=True)
+        subprocess.run('touch /home/{}/.ensure_dir/sparkmagic_kernels_ensured'.format(args.os_user), shell=True, check=True)
+    except:
+        sys.exit(1)
+
+if __name__ == "__main__":
+    if args.dry_run == 'true':
+        parser.print_help()
+    else:
+        install_sparkamagic_kernels(args)
diff --git a/infrastructure-provisioning/src/general/scripts/azure/jupyter_install_dataengine-service_kernels.py b/infrastructure-provisioning/src/general/scripts/azure/jupyter_install_dataengine-service_kernels.py
new file mode 100644
index 0000000..e00f525
--- /dev/null
+++ b/infrastructure-provisioning/src/general/scripts/azure/jupyter_install_dataengine-service_kernels.py
@@ -0,0 +1,105 @@
+#!/usr/bin/python3
+
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+import argparse
+import os
+from datalab.actions_lib import *
+from datalab.meta_lib import *
+from datalab.fab import *
+from fabric import *
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--bucket', type=str, default='')
+parser.add_argument('--cluster_name', type=str, default='')
+parser.add_argument('--dry_run', type=str, default='false')
+parser.add_argument('--hdinsight_version', type=str, default='')
+parser.add_argument('--keyfile', type=str, default='')
+parser.add_argument('--region', type=str, default='')
+parser.add_argument('--notebook_ip', type=str, default='')
+parser.add_argument('--scala_version', type=str, default='')
+parser.add_argument('--edge_user_name', type=str, default='')
+parser.add_argument('--project_name', type=str, default='')
+parser.add_argument('--os_user', type=str, default='')
+parser.add_argument('--edge_hostname', type=str, default='')
+parser.add_argument('--proxy_port', type=str, default='')
+parser.add_argument('--pip_mirror', type=str, default='')
+parser.add_argument('--application', type=str, default='')
+parser.add_argument('--headnode_ip', type=str, default='')
+args = parser.parse_args()
+
+def configure_notebook(args):
+    templates_dir = '/root/templates/'
+    files_dir = '/root/files/'
+    scripts_dir = '/root/scripts/'
+    datalab.fab.conn.put(templates_dir + 'dataengine-service_sparkmagic_config.json', '/tmp/dataengine-service_sparkmagic_config.json')
+    datalab.fab.conn.put(scripts_dir + '{}_dataengine-service_create_configs.py'.format(args.application), '/tmp/create_configs.py')
+    datalab.fab.conn.sudo('\cp /tmp/create_configs.py /usr/local/bin/create_configs.py')
+    datalab.fab.conn.sudo('chmod 755 /usr/local/bin/create_configs.py')
+    datalab.fab.conn.sudo('mkdir -p /usr/lib/python3.8/datalab/')
+    datalab.fab.conn.run('mkdir -p /tmp/datalab_libs/')
+    host_string = args.os_user + "@" + args.notebook_ip
+    datalab.fab.conn.local('rsync -e "ssh -i {}" /usr/lib/python3.8/datalab/*.py {}:/tmp/datalab_libs/'.format(args.keyfile, host_string))
+    datalab.fab.conn.run('chmod a+x /tmp/datalab_libs/*')
+    datalab.fab.conn.sudo('mv /tmp/datalab_libs/* /usr/lib/python3.8/datalab/')
+    if exists(datalab.fab.conn, '/usr/lib64'):
+        datalab.fab.conn.sudo('mkdir -p /usr/lib64/python3.8')
+        datalab.fab.conn.sudo('ln -fs /usr/lib/python3.8/datalab /usr/lib64/python3.8/datalab')
+
+def install_sparkamagic_kernels(args):
+    try:
+        datalab.fab.conn.sudo('jupyter nbextension enable --py --sys-prefix widgetsnbextension')
+        sparkmagic_dir = datalab.fab.conn.sudo(''' bash -l -c 'pip3 show sparkmagic | grep "Location: "' ''').stdout.rstrip("\n\r").split(' ')[1]
+        datalab.fab.conn.sudo('jupyter-kernelspec install {}/sparkmagic/kernels/sparkkernel --prefix=/home/{}/.local/'.format(sparkmagic_dir, args.os_user))
+        datalab.fab.conn.sudo('jupyter-kernelspec install {}/sparkmagic/kernels/pysparkkernel --prefix=/home/{}/.local/'.format(sparkmagic_dir, args.os_user))
+        #datalab.fab.conn.sudo('jupyter-kernelspec install {}/sparkmagic/kernels/sparkrkernel --prefix=/home/{}/.local/'.format(sparkmagic_dir, args.os_user))
+        pyspark_kernel_name = 'PySpark (Python-{0} / Spark-{1} ) [{2}]'.format(args.python_version, args.spark_version,
+                                                                         args.cluster_name)
+        datalab.fab.conn.sudo('sed -i \'s|PySpark|{0}|g\' /home/{1}/.local/share/jupyter/kernels/pysparkkernel/kernel.json'.format(
+            pyspark_kernel_name, args.os_user))
+        spark_kernel_name = 'Spark (Scala-{0} / Spark-{1} ) [{2}]'.format(args.scala_version, args.spark_version,
+                                                                         args.cluster_name)
+        datalab.fab.conn.sudo('sed -i \'s|Spark|{0}|g\' /home/{1}/.local/share/jupyter/kernels/sparkkernel/kernel.json'.format(
+            spark_kernel_name, args.os_user))
+        #sparkr_kernel_name = 'SparkR (R-{0} / Spark-{1} ) [{2}]'.format(args.r_version, args.spark_version,
+        #                                                                   args.cluster_name)
+        #datalab.fab.conn.sudo('sed -i \'s|SparkR|{0}|g\' /home/{1}/.local/share/jupyter/kernels/sparkrkernel/kernel.json'.format(
+        #    sparkr_kernel_name, args.os_user))
+        datalab.fab.conn.sudo('mkdir -p /home/' + args.os_user + '/.sparkmagic')
+        datalab.fab.conn.sudo('cp -f /tmp/dataengine-service_sparkmagic_config.json /home/' + args.os_user + '/.sparkmagic/config.json')
+        datalab.fab.conn.sudo('sed -i \'s|HEADNODEIP:PORT|{0}:{2}|g\' /home/{1}/.sparkmagic/config.json'.format(
+                args.master_ip, args.os_user, args.livy_port))
+        datalab.fab.conn.sudo('chown -R {0}:{0} /home/{0}/.sparkmagic/'.format(args.os_user))
+        datalab.fab.conn.sudo('touch /home/{}/.ensure_dir/sparkmagic_kernels_ensured'.format(args.os_user))
+    except:
+        sys.exit(1)
+
+
+if __name__ == "__main__":
+    global conn
+    conn = init_datalab_connection(args.notebook_ip, args.os_user, args.keyfile)
+    configure_notebook(args)
+    args.spark_version = '3.1.2'
+    args.python_version = '3.8.10'
+    args.livy_port = '8998'
+    args.master_ip = args.headnode_ip
+    install_sparkamagic_kernels(args)
diff --git a/infrastructure-provisioning/src/general/scripts/azure/jupyterlab_configure.py b/infrastructure-provisioning/src/general/scripts/azure/jupyterlab_configure.py
index 077f662..8e9f878 100644
--- a/infrastructure-provisioning/src/general/scripts/azure/jupyterlab_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/azure/jupyterlab_configure.py
@@ -38,7 +38,7 @@
         AzureActions = datalab.actions_lib.AzureActions()
         notebook_config = dict()
         try:
-            notebook_config['exploratory_name'] = os.environ['exploratory_name']
+            notebook_config['exploratory_name'] = os.environ['exploratory_name'].replace('_', '-')
         except:
             notebook_config['exploratory_name'] = ''
         notebook_config['service_base_name'] = os.environ['conf_service_base_name']
@@ -46,8 +46,8 @@
         notebook_config['instance_size'] = os.environ['azure_notebook_instance_size']
         notebook_config['key_name'] = os.environ['conf_key_name']
         notebook_config['user_name'] = os.environ['edge_user_name']
-        notebook_config['project_name'] = os.environ['project_name']
-        notebook_config['endpoint_name'] = os.environ['endpoint_name']
+        notebook_config['project_name'] = os.environ['project_name'].replace('_', '-')
+        notebook_config['endpoint_name'] = os.environ['endpoint_name'].replace('_', '-')
         notebook_config['project_tag'] = notebook_config['project_name']
         notebook_config['endpoint_tag'] = notebook_config['endpoint_name']
         notebook_config['user_keyname'] = notebook_config['project_name']
@@ -313,7 +313,7 @@
             raise Exception
     except Exception as err:
         datalab.fab.append_result("Failed to configure proxy for docker.", str(err))
-        GCPActions().remove_instance(notebook_config['instance_name'], notebook_config['zone'])
+        AzureActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
         sys.exit(1)
 
 
@@ -332,7 +332,7 @@
              raise Exception
     except Exception as err:
         datalab.fab.append_result("Failed to start Jupyter container.", str(err))
-        GCPActions().remove_instance(notebook_config['instance_name'], notebook_config['zone'])
+        AzureActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
         sys.exit(1)
 
     # generating output information
diff --git a/infrastructure-provisioning/src/general/scripts/azure/project_prepare.py b/infrastructure-provisioning/src/general/scripts/azure/project_prepare.py
index a3bc925..ae6ce3e 100644
--- a/infrastructure-provisioning/src/general/scripts/azure/project_prepare.py
+++ b/infrastructure-provisioning/src/general/scripts/azure/project_prepare.py
@@ -825,14 +825,14 @@
                     AzureActions.remove_storage_account(project_conf['resource_group_name'], storage_account.name)
                 if project_conf['shared_storage_account_name'] == storage_account.tags["Name"]:
                     AzureActions.remove_storage_account(project_conf['resource_group_name'], storage_account.name)
-            try:
-                for datalake in AzureMeta.list_datalakes(project_conf['resource_group_name']):
-                    if project_conf['datalake_store_name'] == datalake.tags["Name"]:
-                        AzureActions.remove_datalake_directory(datalake.name,
-                                                                 project_conf['datalake_user_directory_name'])
-            except:
-                logging.info("Data Lake Store directory hasn't been created.")
-            sys.exit(1)
+           # try:
+           #    for datalake in AzureMeta.list_datalakes(project_conf['resource_group_name']):
+           #         if project_conf['datalake_store_name'] == datalake.tags["Name"]:
+           #             AzureActions.remove_datalake_directory(datalake.name,
+           #                                                      project_conf['datalake_user_directory_name'])
+           # except:
+           #     logging.info("Data Lake Store directory hasn't been created.")
+           # sys.exit(1)
 
     if os.environ['conf_os_family'] == 'debian':
         project_conf['initial_user'] = 'ubuntu'
@@ -884,7 +884,7 @@
             if project_conf['shared_storage_account_name'] == storage_account.tags["Name"]:
                 AzureActions.remove_storage_account(project_conf['resource_group_name'], storage_account.name)
         if os.environ['azure_datalake_enable'] == 'true':
-            for datalake in AzureMeta.list_datalakes(project_conf['resource_group_name']):
+           for datalake in AzureMeta.list_datalakes(project_conf['resource_group_name']):
                 if project_conf['datalake_store_name'] == datalake.tags["Name"]:
                     AzureActions.remove_datalake_directory(datalake.name,
                                                            project_conf['datalake_user_directory_name'])
diff --git a/infrastructure-provisioning/src/general/scripts/azure/project_terminate.py b/infrastructure-provisioning/src/general/scripts/azure/project_terminate.py
index 7be7bc5..8b16966 100644
--- a/infrastructure-provisioning/src/general/scripts/azure/project_terminate.py
+++ b/infrastructure-provisioning/src/general/scripts/azure/project_terminate.py
@@ -33,11 +33,27 @@
 
 
 def terminate_edge_node(resource_group_name, service_base_name, project_tag, subnet_name, vpc_name, endpoint_name):
+    logging.info("Terminating Dataengine-service clusters")
+    try:
+        clusters_list = AzureMeta.list_hdinsight_clusters(resource_group_name)
+        if clusters_list:
+            for cluster in clusters_list:
+                if "SBN" in cluster.tags and service_base_name == cluster.tags["SBN"] and \
+                        "project_tag" in cluster.tags and cluster.tags['project_tag'] == project_tag:
+                    AzureActions.terminate_hdinsight_cluster(resource_group_name, cluster.name)
+                    logging.info('The HDinsight cluster {} has been terminated successfully'.format(cluster.name))
+        else:
+            logging.info("There are no HDinsight clusters to terminate.")
+    except Exception as err:
+        datalab.fab.append_result("Failed to terminate dataengine-service", str(err))
+        sys.exit(1)
+
     logging.info("Terminating EDGE, notebook and dataengine virtual machines")
     try:
         for vm in AzureMeta.compute_client.virtual_machines.list(resource_group_name):
             try:
-                if project_tag == vm.tags["project_tag"]:
+                if "SBN" in vm.tags and service_base_name == vm.tags["SBN"] and \
+                        "project_tag" in vm.tags and vm.tags['project_tag'] == project_tag:
                     AzureActions.remove_instance(resource_group_name, vm.name)
                     logging.info("Instance {} has been terminated".format(vm.name))
             except:
@@ -50,7 +66,8 @@
     try:
         for network_interface in AzureMeta.list_network_interfaces(resource_group_name):
             try:
-                if project_tag == network_interface.tags["project_name"]:
+                if "SBN" in network_interface.tags and service_base_name == network_interface.tags["SBN"] and \
+                        "project_tag" in network_interface.tags and network_interface.tags['project_tag'] == project_tag:
                     AzureActions.delete_network_if(resource_group_name, network_interface.name)
                     logging.info("Network interface {} has been removed".format(network_interface.name))
             except:
@@ -63,7 +80,8 @@
     try:
         for static_public_ip in AzureMeta.list_static_ips(resource_group_name):
             try:
-                if project_tag in static_public_ip.tags["project_tag"]:
+                if "SBN" in static_public_ip.tags and service_base_name == static_public_ip.tags["SBN"] and \
+                        "project_tag" in static_public_ip.tags and static_public_ip.tags['project_tag'] == project_tag:
                     AzureActions.delete_static_public_ip(resource_group_name, static_public_ip.name)
                     logging.info("Static public IP {} has been removed".format(static_public_ip.name))
             except:
@@ -76,7 +94,8 @@
     try:
         for disk in AzureMeta.list_disks(resource_group_name):
             try:
-                if project_tag in disk.tags["project_tag"]:
+                if "SBN" in disk.tags and service_base_name == disk.tags["SBN"] and \
+                        "project_tag" in disk.tags and disk.tags['project_tag'] == project_tag:
                     AzureActions.remove_disk(resource_group_name, disk.name)
                     logging.info("Disk {} has been removed".format(disk.name))
             except:
@@ -89,7 +108,8 @@
     try:
         for storage_account in AzureMeta.list_storage_accounts(resource_group_name):
             try:
-                if project_tag == storage_account.tags["project_tag"]:
+                if "SBN" in storage_account.tags and service_base_name == storage_account.tags["SBN"] and \
+                        "project_tag" in storage_account.tags and storage_account.tags['project_tag'] == project_tag:
                     AzureActions.remove_storage_account(resource_group_name, storage_account.name)
                     logging.info("Storage account {} has been terminated".format(storage_account.name))
             except:
@@ -98,24 +118,25 @@
         datalab.fab.append_result("Failed to remove storage accounts.", str(err))
         sys.exit(1)
 
-    logging.info("Deleting Data Lake Store directory")
-    try:
-        for datalake in AzureMeta.list_datalakes(resource_group_name):
-            try:
-                if service_base_name == datalake.tags["SBN"]:
-                    AzureActions.remove_datalake_directory(datalake.name, project_tag + '-folder')
-                    logging.info("Data Lake Store directory {} has been deleted".format(project_tag + '-folder'))
-            except:
-                pass
-    except Exception as err:
-        datalab.fab.append_result("Failed to remove Data Lake.", str(err))
-        sys.exit(1)
+    #logging.info("Deleting Data Lake Store directory")
+    #try:
+    #    for datalake in AzureMeta.list_datalakes(resource_group_name):
+    #        try:
+    #            if service_base_name == datalake.tags["SBN"]:
+    #                AzureActions.remove_datalake_directory(datalake.name, project_tag + '-folder')
+    #                logging.info("Data Lake Store directory {} has been deleted".format(project_tag + '-folder'))
+    #        except:
+    #            pass
+    #except Exception as err:
+    #    datalab.fab.append_result("Failed to remove Data Lake.", str(err))
+    #    sys.exit(1)
 
     logging.info("Removing project specific images")
     try:
         for image in AzureMeta.list_images():
-            if service_base_name == image.tags["SBN"] and project_tag == image.tags["project_tag"] \
-                    and endpoint_name == image.tags["endpoint_tag"]:
+            if "SBN" in image.tags and service_base_name == image.tags["SBN"] and \
+                    "project_tag" in image.tags and image.tags['project_tag'] == project_tag and \
+                    "endpoint_tag" in image.tags and endpoint_name == image.tags["endpoint_tag"]:
                 AzureActions.remove_image(resource_group_name, image.name)
                 logging.info("Image {} has been removed".format(image.name))
     except Exception as err:
@@ -132,7 +153,8 @@
                                                                       project_conf['endpoint_name']))
         for sg in AzureMeta.network_client.network_security_groups.list(resource_group_name):
             try:
-                if project_tag == sg.tags["project_tag"]:
+                if "SBN" in sg.tags and service_base_name == sg.tags["SBN"] and \
+                        "project_tag" in sg.tags and sg.tags['project_tag'] == project_tag:
                     AzureActions.remove_security_group(resource_group_name, sg.name)
                     logging.info("Security group {} has been terminated".format(sg.name))
             except:
diff --git a/infrastructure-provisioning/src/general/scripts/azure/rstudio_install_dataengine-service_kernels.py b/infrastructure-provisioning/src/general/scripts/azure/rstudio_install_dataengine-service_kernels.py
new file mode 100644
index 0000000..06d8842
--- /dev/null
+++ b/infrastructure-provisioning/src/general/scripts/azure/rstudio_install_dataengine-service_kernels.py
@@ -0,0 +1,26 @@
+#!/usr/bin/python3
+
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+
+if __name__ == "__main__":
+    pass
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/general/scripts/azure/ssn_configure.py b/infrastructure-provisioning/src/general/scripts/azure/ssn_configure.py
index 3e8dcdc..b0d26cb 100644
--- a/infrastructure-provisioning/src/general/scripts/azure/ssn_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/azure/ssn_configure.py
@@ -36,9 +36,9 @@
 if __name__ == "__main__":
     def clear_resources():
         AzureActions.remove_instance(ssn_conf['resource_group_name'], ssn_conf['instance_name'])
-        for datalake in AzureMeta.list_datalakes(ssn_conf['resource_group_name']):
-            if ssn_conf['datalake_store_name'] == datalake.tags["Name"]:
-                AzureActions.delete_datalake_store(ssn_conf['resource_group_name'], datalake.name)
+        # for datalake in AzureMeta.list_datalakes(ssn_conf['resource_group_name']):
+        #    if ssn_conf['datalake_store_name'] == datalake.tags["Name"]:
+        #        AzureActions.delete_datalake_store(ssn_conf['resource_group_name'], datalake.name)
         if 'azure_security_group_name' not in os.environ:
             AzureActions.remove_security_group(ssn_conf['resource_group_name'], ssn_conf['security_group_name'])
         if 'azure_subnet_name' not in os.environ:
@@ -146,7 +146,7 @@
 
     try:
         logging.info('[INSTALLING PREREQUISITES TO SSN INSTANCE]')
-        params = "--hostname {} --keyfile {} --pip_packages 'backoff bcrypt==3.1.7 argparse fabric==1.14.0 pymongo pyyaml " \
+        params = "--hostname {} --keyfile {} --pip_packages 'backoff cryptography==36.0.2 bcrypt==3.1.7 argparse fabric==1.14.0 pymongo pyyaml " \
                  "pycryptodome azure==2.0.0' --user {} --region {}".format(ssn_conf['instance_host'],
                                                                        ssn_conf['ssh_key_path'],
                                                                        ssn_conf['datalab_ssh_user'],
@@ -187,7 +187,8 @@
                              {"name": "zeppelin", "tag": "latest"},
                              {"name": "tensor", "tag": "latest"},
                              {"name": "deeplearning", "tag": "latest"},
-                             {"name": "dataengine", "tag": "latest"}]
+                             {"name": "dataengine", "tag": "latest"},
+                             {"name": "dataengine-service", "tag": "latest"}]
         params = "--hostname {} --keyfile {} --additional_config '{}' --os_family {} --os_user {} --datalab_path {} " \
                  "--cloud_provider {} --region {}".format(ssn_conf['instance_host'], ssn_conf['ssh_key_path'],
                                                           json.dumps(additional_config), os.environ['conf_os_family'],
@@ -483,15 +484,15 @@
             ssn_conf['tenant_id'] = json.dumps(AzureMeta.sp_creds['tenantId']).replace('"', '')
             ssn_conf['subscription_id'] = json.dumps(AzureMeta.sp_creds['subscriptionId']).replace('"', '')
             ssn_conf['datalake_application_id'] = os.environ['azure_application_id']
-            for datalake in AzureMeta.list_datalakes(ssn_conf['resource_group_name']):
-                if ssn_conf['datalake_store_name'] == datalake.tags["Name"]:
-                    datalake_store_name = datalake.name
+           # for datalake in AzureMeta.list_datalakes(ssn_conf['resource_group_name']):
+           #     if ssn_conf['datalake_store_name'] == datalake.tags["Name"]:
+           #         datalake_store_name = datalake.name
         params = "--hostname {} --keyfile {} --datalab_path {} --os_user {} --os_family {} --request_id {} \
                  --resource {} --service_base_name {} --cloud_provider {} --billing_enabled {} --authentication_file {} \
                  --offer_number {} --currency {} --locale {} --region_info {}  --ldap_login {} --tenant_id {} \
                  --application_id {} --datalake_store_name {} --cloud_params '{}' --subscription_id {}  \
                  --validate_permission_scope {} --default_endpoint_name {} --keycloak_client_id {} \
-                 --keycloak_client_secret {} --keycloak_auth_server_url {}". \
+                 --keycloak_client_secret {} --keycloak_auth_server_url {} --keycloak_realm_name {}". \
             format(ssn_conf['instnace_ip'], ssn_conf['ssh_key_path'], os.environ['ssn_datalab_path'],
                    ssn_conf['datalab_ssh_user'], os.environ['conf_os_family'], os.environ['request_id'],
                    os.environ['conf_resource'], ssn_conf['service_base_name'], os.environ['conf_cloud_provider'],
@@ -502,7 +503,8 @@
                    ssn_conf['subscription_id'], os.environ['azure_validate_permission_scope'],
                    ssn_conf['default_endpoint_name'],
                    os.environ['keycloak_client_name'], os.environ['keycloak_client_secret'],
-                   os.environ['keycloak_auth_server_url'])
+                   os.environ['keycloak_auth_server_url'],
+                   os.environ['keycloak_realm_name'])
         subprocess.run("~/scripts/{}.py {}".format('configure_ui', params), shell=True, check=True)
     except Exception as err:
         traceback.print_exc()
diff --git a/infrastructure-provisioning/src/general/scripts/azure/ssn_prepare.py b/infrastructure-provisioning/src/general/scripts/azure/ssn_prepare.py
index 8862b0d..3cd6868 100644
--- a/infrastructure-provisioning/src/general/scripts/azure/ssn_prepare.py
+++ b/infrastructure-provisioning/src/general/scripts/azure/ssn_prepare.py
@@ -263,9 +263,9 @@
         except Exception as err:
             traceback.print_exc()
             datalab.fab.append_result("Failed to create Data Lake Store.", str(err))
-            for datalake in AzureMeta.list_datalakes(ssn_conf['resource_group_name']):
-                if ssn_conf['datalake_store_name'] == datalake.tags["Name"]:
-                    AzureActions.delete_datalake_store(ssn_conf['resource_group_name'], datalake.name)
+           # for datalake in AzureMeta.list_datalakes(ssn_conf['resource_group_name']):
+           #     if ssn_conf['datalake_store_name'] == datalake.tags["Name"]:
+           #         AzureActions.delete_datalake_store(ssn_conf['resource_group_name'], datalake.name)
             if 'azure_security_group_name' not in os.environ:
                 AzureActions.remove_security_group(ssn_conf['resource_group_name'], ssn_conf['security_group_name'])
             if 'azure_subnet_name' not in os.environ:
@@ -304,9 +304,9 @@
             AzureActions.remove_instance(ssn_conf['resource_group_name'], ssn_conf['instance_name'])
         except:
             logging.info("The instance {} hasn't been created".format(ssn_conf['instance_name']))
-        for datalake in AzureMeta.list_datalakes(ssn_conf['resource_group_name']):
-            if ssn_conf['datalake_store_name'] == datalake.tags["Name"]:
-                AzureActions.delete_datalake_store(ssn_conf['resource_group_name'], datalake.name)
+       # for datalake in AzureMeta.list_datalakes(ssn_conf['resource_group_name']):
+       #     if ssn_conf['datalake_store_name'] == datalake.tags["Name"]:
+       #         AzureActions.delete_datalake_store(ssn_conf['resource_group_name'], datalake.name)
         if 'azure_security_group_name' not in os.environ:
             AzureActions.remove_security_group(ssn_conf['resource_group_name'], ssn_conf['security_group_name'])
         if 'azure_subnet_name' not in os.environ:
diff --git a/infrastructure-provisioning/src/general/scripts/azure/ssn_terminate.py b/infrastructure-provisioning/src/general/scripts/azure/ssn_terminate.py
index f29198d..6cce9b3 100644
--- a/infrastructure-provisioning/src/general/scripts/azure/ssn_terminate.py
+++ b/infrastructure-provisioning/src/general/scripts/azure/ssn_terminate.py
@@ -35,6 +35,16 @@
 
 
 def terminate_ssn_node(resource_group_name, service_base_name, vpc_name, region):
+    logging.info("Terminating HDINSIGHT clusters")
+    try:
+        for cluster in AzureMeta.list_hdinsight_clusters(resource_group_name):
+            if "SBN" in cluster.tags and service_base_name == cluster.tags["SBN"]:
+                AzureActions.terminate_hdinsight_cluster(resource_group_name, cluster.name)
+                logging.info("Cluster {} has been terminated".format(cluster.name))
+    except Exception as err:
+        datalab.fab.append_result("Failed to terminate HDINSIGHT clusters", str(err))
+        sys.exit(1)
+
     logging.info("Terminating instances")
     try:
         for vm in AzureMeta.compute_client.virtual_machines.list(resource_group_name):
@@ -85,15 +95,15 @@
         datalab.fab.append_result("Failed to remove storage accounts", str(err))
         sys.exit(1)
 
-    logging.info("Removing Data Lake Store")
-    try:
-        for datalake in AzureMeta.list_datalakes(resource_group_name):
-            if "SBN" in datalake.tags and service_base_name == datalake.tags["SBN"]:
-                AzureActions.delete_datalake_store(resource_group_name, datalake.name)
-                logging.info("Data Lake Store {} has been terminated".format(datalake.name))
-    except Exception as err:
-        datalab.fab.append_result("Failed to remove Data Lake", str(err))
-        sys.exit(1)
+   # logging.info("Removing Data Lake Store")
+   # try:
+   #     for datalake in AzureMeta.list_datalakes(resource_group_name):
+   #         if "SBN" in datalake.tags and service_base_name == datalake.tags["SBN"]:
+   #             AzureActions.delete_datalake_store(resource_group_name, datalake.name)
+   #             logging.info("Data Lake Store {} has been terminated".format(datalake.name))
+   # except Exception as err:
+   #     datalab.fab.append_result("Failed to remove Data Lake", str(err))
+   #     sys.exit(1)
 
     logging.info("Removing images")
     try:
@@ -182,16 +192,16 @@
                                               headers={"Authorization": "Bearer " + keycloak_token.get("access_token"),
                                                        "Content-Type": "application/json"})
         json_keycloak_client_id = json.loads(keycloak_get_id_client.text)
-        keycloak_id_client = json_keycloak_client_id[0]['id']
-
-        keycloak_client_delete_url = '{0}/admin/realms/{1}/clients/{2}'.format(os.environ['keycloak_auth_server_url'],
-                                                                               os.environ['keycloak_realm_name'],
-                                                                               keycloak_id_client)
-
-        keycloak_client = requests.delete(
-            keycloak_client_delete_url,
-            headers={"Authorization": "Bearer {}".format(keycloak_token.get("access_token")),
-                     "Content-Type": "application/json"})
+        if not json_keycloak_client_id:
+            logging.info("Unable to find {}-* Keycloak clients".format(ssn_conf['service_base_name']))
+        else:
+            keycloak_id_client = json_keycloak_client_id[0]['id']
+            keycloak_client_delete_url = '{0}/admin/realms/{1}/clients/{2}'.format(os.environ['keycloak_auth_server_url'],
+                                                                                   os.environ['keycloak_realm_name'],
+                                                                                   keycloak_id_client)
+            keycloak_client = requests.delete(keycloak_client_delete_url,
+                                              headers={"Authorization": "Bearer {}".format(keycloak_token.get("access_token")),
+                                                       "Content-Type": "application/json"})
     except Exception as err:
         logging.info("Failed to remove ssn client from Keycloak", str(err))
 
diff --git a/infrastructure-provisioning/src/general/scripts/azure/zeppelin_dataengine-service_create_configs.py b/infrastructure-provisioning/src/general/scripts/azure/zeppelin_dataengine-service_create_configs.py
new file mode 100644
index 0000000..08c71b6
--- /dev/null
+++ b/infrastructure-provisioning/src/general/scripts/azure/zeppelin_dataengine-service_create_configs.py
@@ -0,0 +1,95 @@
+#!/usr/bin/python3
+
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+import argparse
+import subprocess
+from datalab.actions_lib import configure_zeppelin_hdinsight_interpreter  # , jars, yarn, install_hdinsight_spark, spark_defaults, installing_python
+from datalab.common_lib import *
+# from datalab.fab import configuring_notebook, update_zeppelin_interpreters
+from datalab.notebook_lib import *
+from fabric import *
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--bucket', type=str, default='')
+parser.add_argument('--cluster_name', type=str, default='')
+parser.add_argument('--dry_run', type=str, default='false')
+parser.add_argument('--hdinsight_version', type=str, default='')
+parser.add_argument('--spark_version', type=str, default='')
+parser.add_argument('--scala_version', type=str, default='')
+parser.add_argument('--hadoop_version', type=str, default='')
+parser.add_argument('--matplotlib_version', type=str, default='')
+parser.add_argument('--region', type=str, default='')
+parser.add_argument('--excluded_lines', type=str, default='')
+parser.add_argument('--project_name', type=str, default='')
+parser.add_argument('--os_user', type=str, default='')
+parser.add_argument('--edge_hostname', type=str, default='')
+parser.add_argument('--proxy_port', type=str, default='')
+parser.add_argument('--livy_version', type=str, default='')
+parser.add_argument('--multiple_clusters', type=str, default='')
+parser.add_argument('--numpy_version', type=str, default='')
+parser.add_argument('--application', type=str, default='')
+parser.add_argument('--r_enabled', type=str, default='')
+parser.add_argument('--headnode_ip', type=str, default='')
+args = parser.parse_args()
+
+hdinsight_dir = '/opt/' + args.hdinsight_version + '/jars/'
+kernels_dir = '/home/' + args.os_user + '/.local/share/jupyter/kernels/'
+spark_dir = '/opt/' + args.hdinsight_version + '/' + args.cluster_name + '/spark/'
+yarn_dir = '/opt/' + args.hdinsight_version + '/' + args.cluster_name + '/conf/'
+
+
+def install_remote_livy(args):
+    subprocess.run('sudo chown ' + args.os_user + ':' + args.os_user + ' -R /opt/zeppelin/', shell=True, check=True)
+    subprocess.run('sudo service zeppelin-notebook stop', shell=True, check=True)
+    subprocess.run('sudo -i wget http://archive.cloudera.com/beta/livy/livy-server-' + args.livy_version + '.zip -O /opt/'
+          + args.hdinsight_version + '/' + args.cluster_name + '/livy-server-' + args.livy_version + '.zip', shell=True, check=True)
+    subprocess.run('sudo unzip /opt/'
+          + args.hdinsight_version + '/' + args.cluster_name + '/livy-server-' + args.livy_version + '.zip -d /opt/'
+          + args.hdinsight_version + '/' + args.cluster_name + '/', shell=True, check=True)
+    subprocess.run('sudo mv /opt/' + args.hdinsight_version + '/' + args.cluster_name + '/livy-server-' + args.livy_version +
+          '/ /opt/' + args.hdinsight_version + '/' + args.cluster_name + '/livy/', shell=True, check=True)
+    livy_path = '/opt/' + args.hdinsight_version + '/' + args.cluster_name + '/livy/'
+    subprocess.run('sudo mkdir -p ' + livy_path + '/logs', shell=True, check=True)
+    subprocess.run('sudo mkdir -p /var/run/livy', shell=True, check=True)
+    subprocess.run('sudo chown ' + args.os_user + ':' + args.os_user + ' -R /var/run/livy', shell=True, check=True)
+    subprocess.run('sudo chown ' + args.os_user + ':' + args.os_user + ' -R ' + livy_path, shell=True, check=True)
+    subprocess.run('sudo service zeppelin-notebook start', shell=True, check=True)
+
+
+if __name__ == "__main__":
+    if args.dry_run == 'true':
+        parser.print_help()
+    else:
+        # result = prepare(hdinsight_dir, yarn_dir)
+        # if result == False :
+        #     jars(args, hdinsight_dir)
+        # yarn(args, yarn_dir)
+        # install_hdinsight_spark(args)
+        # spark_defaults(args)
+        # configuring_notebook(args.hdinsight_version)
+        # if args.multiple_clusters == 'true':
+        #     install_remote_livy(args)
+        # installing_python(args.region, args.bucket, args.project_name, args.cluster_name, args.application,
+        #                   args.numpy_version, args.matplotlib_version)
+        configure_zeppelin_hdinsight_interpreter(args.cluster_name, args.os_user, args.headnode_ip)
+        # update_zeppelin_interpreters(args.multiple_clusters, args.r_enabled)
diff --git a/infrastructure-provisioning/src/general/scripts/azure/zeppelin_install_dataengine-service_kernels.py b/infrastructure-provisioning/src/general/scripts/azure/zeppelin_install_dataengine-service_kernels.py
new file mode 100644
index 0000000..80211ae
--- /dev/null
+++ b/infrastructure-provisioning/src/general/scripts/azure/zeppelin_install_dataengine-service_kernels.py
@@ -0,0 +1,105 @@
+#!/usr/bin/python3
+
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+import argparse
+import os
+from datalab.meta_lib import *
+from datalab.fab import init_datalab_connection
+from fabric import *
+from patchwork.files import exists
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--bucket', type=str, default='')
+parser.add_argument('--cluster_name', type=str, default='')
+parser.add_argument('--dry_run', type=str, default='false')
+parser.add_argument('--hdinsight_version', type=str, default='')
+parser.add_argument('--keyfile', type=str, default='')
+parser.add_argument('--region', type=str, default='')
+parser.add_argument('--notebook_ip', type=str, default='')
+parser.add_argument('--scala_version', type=str, default='')
+parser.add_argument('--hdinsight_excluded_spark_properties', type=str, default='')
+parser.add_argument('--project_name', type=str, default='')
+parser.add_argument('--os_user', type=str, default='')
+parser.add_argument('--edge_hostname', type=str, default='')
+parser.add_argument('--proxy_port', type=str, default='')
+parser.add_argument('--application', type=str, default='')
+parser.add_argument('--headnode_ip', type=str, default='')
+args = parser.parse_args()
+
+
+def configure_notebook(args):
+    templates_dir = '/root/templates/'
+    scripts_dir = '/root/scripts/'
+    if os.environ['notebook_multiple_clusters'] == 'true':
+        conn.put(templates_dir + 'dataengine-service_interpreter_livy.json', '/tmp/dataengine-service_interpreter.json')
+    else:
+        conn.put(templates_dir + 'dataengine-service_interpreter_livy.json', '/tmp/dataengine-service_interpreter.json')
+    conn.put('{}{}_dataengine-service_create_configs.py'.format(scripts_dir, args.application),
+             '/tmp/zeppelin_dataengine-service_create_configs.py')
+    conn.sudo('\cp /tmp/zeppelin_dataengine-service_create_configs.py '
+              '/usr/local/bin/zeppelin_dataengine-service_create_configs.py')
+    conn.sudo('chmod 755 /usr/local/bin/zeppelin_dataengine-service_create_configs.py')
+    conn.sudo('mkdir -p /usr/lib/python3.8/datalab/')
+    conn.run('mkdir -p /tmp/datalab_libs/')
+    conn.local('rsync -e "ssh -i {}" /usr/lib/python3.8/datalab/*.py {}@{}:/tmp/datalab_libs/'.format(args.keyfile, args.os_user, args.notebook_ip))
+    conn.run('chmod a+x /tmp/datalab_libs/*')
+    conn.sudo('mv /tmp/datalab_libs/* /usr/lib/python3.8/datalab/')
+    if exists(conn, '/usr/lib64'):
+        conn.sudo('mkdir -p /usr/lib64/python3.8')
+        conn.sudo('ln -fs /usr/lib/python3.8/datalab /usr/lib64/python3.8/datalab')
+
+
+if __name__ == "__main__":
+    global conn
+    conn = init_datalab_connection(args.notebook_ip, args.os_user, args.keyfile)
+    configure_notebook(args)
+    spark_version = "None"  #get_spark_version(args.cluster_name)
+    hadoop_version = "None"  #get_hadoop_version(args.cluster_name)
+    livy_version = os.environ['notebook_livy_version']
+    r_enabled = os.environ['notebook_r_enabled']
+    numpy_version = os.environ['notebook_numpy_version']
+    matplotlib_version = os.environ['notebook_matplotlib_version']
+    command = "/usr/bin/python3 /usr/local/bin/zeppelin_dataengine-service_create_configs.py " \
+              "--cluster_name {1} " \
+              "--os_user {8} " \
+              "--headnode_ip {18}" \
+        .format(args.bucket,
+                args.cluster_name,
+                args.hdinsight_version,
+                spark_version,
+                hadoop_version,
+                args.region,
+                args.hdinsight_excluded_spark_properties,
+                args.project_name,
+                args.os_user,
+                args.edge_hostname,
+                args.proxy_port,
+                args.scala_version,
+                livy_version,
+                os.environ['notebook_multiple_clusters'],
+                numpy_version,
+                matplotlib_version,
+                args.application,
+                r_enabled,
+                args.headnode_ip)
+    conn.sudo(command)
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/common_collect_data.py b/infrastructure-provisioning/src/general/scripts/gcp/common_collect_data.py
index 1f8527e..e54828a 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/common_collect_data.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/common_collect_data.py
@@ -62,6 +62,12 @@
             statuses['cluster'] = data_clusters
         except:
             logging.error("Clusters JSON wasn't been provided")
+        try:
+            id_images = get_id_resourses(data.get('image'))
+            data_images = GCPMeta().get_list_image_statuses(id_images)
+            statuses['image'] = data_images
+        except:
+            logging.error("Images JSON wasn't been provided")
         with open('/root/result.json', 'w') as outfile:
             json.dump(statuses, outfile)
     except Exception as err:
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/common_create_bucket.py b/infrastructure-provisioning/src/general/scripts/gcp/common_create_bucket.py
index 34352e5..389ca10 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/common_create_bucket.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/common_create_bucket.py
@@ -31,6 +31,9 @@
 parser = argparse.ArgumentParser()
 parser.add_argument('--bucket_name', type=str, default='')
 parser.add_argument('--tags', type=str, default='')
+parser.add_argument('--versioning_enabled', type=str, default='false')
+parser.add_argument('--cmek_resource_name', type=str, default='')
+parser.add_argument('--lifecycle_rules', type=str, default='')
 args = parser.parse_args()
 
 if __name__ == "__main__":
@@ -40,7 +43,8 @@
         else:
             logging.info("Creating Bucket {}".format(args.bucket_name))
             GCPActions().create_bucket(args.bucket_name)
-            GCPActions().add_bucket_labels(args.bucket_name, json.loads(args.tags))
+            GCPActions().add_bucket_labels_vers_cmek(args.bucket_name, json.loads(args.tags), args.versioning_enabled,
+                                                     args.cmek_resource_name, json.loads(args.lifecycle_rules))
     else:
         parser.print_help()
         sys.exit(2)
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/common_create_instance.py b/infrastructure-provisioning/src/general/scripts/gcp/common_create_instance.py
index d780b44..1890c98 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/common_create_instance.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/common_create_instance.py
@@ -50,6 +50,9 @@
 parser.add_argument('--network_tag', type=str, default='')
 parser.add_argument('--cluster_name', type=str, default='')
 parser.add_argument('--service_base_name', type=str, default='')
+parser.add_argument('--os_login_enabled', type=str, default='FALSE')
+parser.add_argument('--block_project_ssh_keys', type=str, default='FALSE')
+parser.add_argument('--rsa_encrypted_csek', type=str, default='')
 args = parser.parse_args()
 
 
@@ -65,7 +68,8 @@
                                          args.secondary_image_name, args.service_account_name, args.instance_class,
                                          args.network_tag, json.loads(args.labels), args.static_ip,
                                          args.primary_disk_size, args.secondary_disk_size, args.gpu_accelerator_type,
-                                         args.gpu_accelerator_count)
+                                         args.gpu_accelerator_count, args.os_login_enabled, args.block_project_ssh_keys,
+                                         args.rsa_encrypted_csek)
     else:
         parser.print_help()
         sys.exit(2)
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/common_create_notebook_image.py b/infrastructure-provisioning/src/general/scripts/gcp/common_create_notebook_image.py
index 1be0d2e..cf603d0 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/common_create_notebook_image.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/common_create_notebook_image.py
@@ -60,16 +60,23 @@
                                            "image": image_conf['image_name'],
                                            os.environ['conf_billing_tag_key']: os.environ['conf_billing_tag_value']}
         image_conf['instance_name'] = '{0}-{1}-{2}-nb-{3}'.format(image_conf['service_base_name'],
-                                                                       image_conf['project_name'],
-                                                                       image_conf['endpoint_name'],
-                                                                       image_conf['exploratory_name'])
+                                                                  image_conf['project_name'],
+                                                                  image_conf['endpoint_name'],
+                                                                  image_conf['exploratory_name'])
+
+        if "gcp_wrapped_csek" in os.environ:
+            image_conf['gcp_wrapped_csek'] = os.environ['gcp_wrapped_csek']
+        else:
+            image_conf['gcp_wrapped_csek'] = ''
+
         image_conf['zone'] = os.environ['gcp_zone']
         logging.info('[CREATING IMAGE]')
         primary_image_id = GCPMeta.get_image_by_name(image_conf['expected_primary_image_name'])
         if primary_image_id == '':
             image_id_list = GCPActions.create_image_from_instance_disks(
                 image_conf['expected_primary_image_name'], image_conf['expected_secondary_image_name'],
-                image_conf['instance_name'], image_conf['zone'], image_conf['image_labels'])
+                image_conf['instance_name'], image_conf['zone'], image_conf['image_labels'],
+                image_conf['gcp_wrapped_csek'])
             if image_id_list and image_id_list[0] != '':
                 logging.info("Image of primary disk was successfully created. It's ID is {}".format(image_id_list[0]))
             else:
@@ -81,9 +88,10 @@
             with open("/root/result.json", 'w') as result:
                 res = {"primary_image_name": image_conf['expected_primary_image_name'],
                        "secondary_image_name": image_conf['expected_secondary_image_name'],
+                       "full_image_name": image_conf['expected_primary_image_name'],
                        "project_name": image_conf['project_name'],
                        "application": image_conf['application'],
-                       "status": "created",
+                       "status": "active",
                        "Action": "Create image from notebook"}
                 result.write(json.dumps(res))
     except Exception as err:
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/common_prepare_notebook.py b/infrastructure-provisioning/src/general/scripts/gcp/common_prepare_notebook.py
index dbacfab..a4e5a24 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/common_prepare_notebook.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/common_prepare_notebook.py
@@ -90,7 +90,8 @@
                                                                        notebook_config['project_name'],
                                                                        notebook_config['endpoint_name'],
                                                                        notebook_config['exploratory_name'])
-        notebook_config['primary_disk_size'] = (lambda x: '60' if x == 'deeplearning' else '20')(
+        notebook_config['primary_disk_size'] = (lambda x: '60' if x == 'deeplearning' else ('30' if x == 'tensor'
+                                                                                            else '20'))(
             os.environ['application'])
         notebook_config['secondary_disk_size'] = os.environ['notebook_disk_size']
 
@@ -148,9 +149,18 @@
             notebook_config['secondary_image_name'] = 'global/images/{}'.format(
                 notebook_config['secondary_image_name'].get('name'))
 
+        notebook_config['gcp_os_login_enabled'] = os.environ['gcp_os_login_enabled']
+        notebook_config['gcp_block_project_ssh_keys'] = os.environ['gcp_block_project_ssh_keys']
+
+        if "gcp_wrapped_csek" in os.environ:
+            notebook_config['gcp_wrapped_csek'] = os.environ['gcp_wrapped_csek']
+        else:
+            notebook_config['gcp_wrapped_csek'] = ''
+
         notebook_config['gpu_accelerator_type'] = 'None'
         notebook_config['gpu_accelerator_count'] = 'None'
 
+
         if os.environ['application'] in ('tensor', 'tensor-rstudio', 'deeplearning') or os.environ['gpu_enabled'] == 'True':
             if os.environ['gpuType'] != '':
                 notebook_config['gpu_accelerator_type'] = os.environ['gpuType']
@@ -158,6 +168,10 @@
             else:
                 notebook_config['gpu_accelerator_type'] = os.environ['gcp_gpu_accelerator_type']
 
+        if os.environ['application'] in ('jupyter-gpu', 'jupyter-conda'):
+            notebook_config['gpu_accelerator_type'] = os.environ['gcp_jupyter_gpu_type']
+            notebook_config['gpu_accelerator_count'] = '1'
+
         notebook_config['network_tag'] = '{0}-{1}-{2}-ps'.format(notebook_config['service_base_name'],
                                                                  notebook_config['project_name'],
                                                                  notebook_config['endpoint_name'])
@@ -192,8 +206,9 @@
         params = "--instance_name {0} --region {1} --zone {2} --vpc_name {3} --subnet_name {4} --instance_size {5} " \
                  "--ssh_key_path {6} --initial_user {7} --service_account_name {8} --image_name {9} " \
                  "--secondary_image_name {10} --instance_class {11} --primary_disk_size {12} " \
-                 "--secondary_disk_size {13} --gpu_accelerator_type {14} --gpu_accelerator_count {15} --network_tag {16} --labels '{17}' " \
-                 "--service_base_name {18}".\
+                 "--secondary_disk_size {13} --gpu_accelerator_type {14} --gpu_accelerator_count {15} " \
+                 "--network_tag {16} --labels '{17}' --service_base_name {18} --os_login_enabled FALSE " \
+                 "--block_project_ssh_keys {20} --rsa_encrypted_csek '{21}'".\
             format(notebook_config['instance_name'], notebook_config['region'], notebook_config['zone'],
                    notebook_config['vpc_name'], notebook_config['subnet_name'], notebook_config['instance_size'],
                    notebook_config['ssh_key_path'], notebook_config['initial_user'],
@@ -201,7 +216,9 @@
                    notebook_config['secondary_image_name'], 'notebook', notebook_config['primary_disk_size'],
                    notebook_config['secondary_disk_size'], notebook_config['gpu_accelerator_type'],
                    notebook_config['gpu_accelerator_count'], notebook_config['network_tag'],
-                   json.dumps(notebook_config['labels']), notebook_config['service_base_name'])
+                   json.dumps(notebook_config['labels']), notebook_config['service_base_name'],
+                   notebook_config['gcp_os_login_enabled'], notebook_config['gcp_block_project_ssh_keys'],
+                   notebook_config['gcp_wrapped_csek'])
         try:
             subprocess.run("~/scripts/{}.py {}".format('common_create_instance', params), shell=True, check=True)
         except:
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/common_start_notebook.py b/infrastructure-provisioning/src/general/scripts/gcp/common_start_notebook.py
index f63d6fb..e854681 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/common_start_notebook.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/common_start_notebook.py
@@ -41,12 +41,17 @@
     notebook_config['service_base_name'] = (os.environ['conf_service_base_name'])
     notebook_config['notebook_name'] = os.environ['notebook_instance_name']
     notebook_config['zone'] = os.environ['gcp_zone']
+    if "gcp_wrapped_csek" in os.environ:
+        notebook_config['gcp_wrapped_csek'] = os.environ['gcp_wrapped_csek']
+    else:
+        notebook_config['gcp_wrapped_csek'] = ''
 
     try:
         logging.info('[START NOTEBOOK]')
         try:
             logging.info("Starting notebook")
-            GCPActions.start_instance(notebook_config['notebook_name'], notebook_config['zone'])
+            GCPActions.start_instance(notebook_config['notebook_name'], notebook_config['zone'],
+                                      notebook_config['gcp_wrapped_csek'])
         except Exception as err:
             traceback.print_exc()
             datalab.fab.append_result("Failed to start notebook.", str(err))
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/common_terminate_notebook.py b/infrastructure-provisioning/src/general/scripts/gcp/common_terminate_notebook.py
index db40b05..5acc11a 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/common_terminate_notebook.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/common_terminate_notebook.py
@@ -25,6 +25,7 @@
 import datalab.fab
 import datalab.meta_lib
 import json
+import requests
 from datalab.logger import logging
 import os
 import sys
@@ -73,6 +74,45 @@
     except Exception as err:
         datalab.fab.append_result("Failed to terminate instance", str(err))
         sys.exit(1)
+        
+    if os.environ['notebook_create_keycloak_client'] == 'True':
+        logging.info("Terminating notebook keycloak client")
+        try:
+            keycloak_auth_server_url = '{}/realms/master/protocol/openid-connect/token'.format(
+                os.environ['keycloak_auth_server_url'])
+            keycloak_client_url = '{0}/admin/realms/{1}/clients'.format(os.environ['keycloak_auth_server_url'],
+                                                                        os.environ['keycloak_realm_name'])
+
+            keycloak_auth_data = {
+                "username": os.environ['keycloak_user'],
+                "password": os.environ['keycloak_user_password'],
+                "grant_type": "password",
+                "client_id": "admin-cli",
+            }
+
+            client_params = {
+                "clientId": "{}-{}-{}-{}".format(notebook_config['service_base_name'], notebook_config['project_name'],
+                                                 notebook_config['endpoint_name'], notebook_config['exploratory_name'])
+            }
+
+            keycloak_token = requests.post(keycloak_auth_server_url, data=keycloak_auth_data).json()
+
+            keycloak_get_id_client = requests.get(keycloak_client_url, data=keycloak_auth_data, params=client_params,
+                                                  headers={"Authorization": "Bearer " + keycloak_token.get("access_token"),
+                                                           "Content-Type": "application/json"})
+            json_keycloak_client_id = json.loads(keycloak_get_id_client.text)
+            keycloak_id_client = json_keycloak_client_id[0]['id']
+
+            keycloak_client_delete_url = '{0}/admin/realms/{1}/clients/{2}'.format(os.environ['keycloak_auth_server_url'],
+                                                                                   os.environ['keycloak_realm_name'],
+                                                                                   keycloak_id_client)
+
+            requests.delete(keycloak_client_delete_url,
+                            headers={"Authorization": "Bearer " + keycloak_token.get("access_token"),
+                                     "Content-Type": "application/json"})
+        except Exception as err:
+            logging.error("Failed to remove project client from Keycloak", str(err))
+        
 
 
 if __name__ == "__main__":
@@ -91,6 +131,10 @@
                                                                  notebook_config['endpoint_name'])
     notebook_config['gcp_region'] = os.environ['gcp_region']
     notebook_config['gcp_zone'] = os.environ['gcp_zone']
+    try:
+        notebook_config['exploratory_name'] = (os.environ['exploratory_name']).replace('_', '-').lower()
+    except:
+        notebook_config['exploratory_name'] = ''
 
     try:
         logging.info('[TERMINATE NOTEBOOK]')
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/common_terminate_notebook_image.py b/infrastructure-provisioning/src/general/scripts/gcp/common_terminate_notebook_image.py
index a448841..83efb9e 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/common_terminate_notebook_image.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/common_terminate_notebook_image.py
@@ -33,7 +33,7 @@
         image_conf = dict()
         GCPMeta = datalab.meta_lib.GCPMeta()
         GCPActions = datalab.actions_lib.GCPActions()
-        image_conf['image_name'] = os.environ['notebook_image_name']
+        image_conf['image_name'] = os.environ['notebook_image_name'].replace('_', '-').lower()
         image_conf['service_base_name'] = os.environ['conf_service_base_name'] = datalab.fab.replace_multi_symbols(
             os.environ['conf_service_base_name'][:20], '-', True)
         image_conf['endpoint_name'] = (os.environ['endpoint_name']).replace('_', '-').lower()
@@ -48,13 +48,16 @@
             os.environ['application'], image_conf['image_name']).lower()
         primary_image_id = GCPMeta.get_image_by_name(image_conf['expected_primary_image_name'])
         if primary_image_id != '':
-            GCPActions.remove_image(notebook_config['expected_primary_image_name'])
-            GCPActions.remove_image(notebook_config['expected_secondary_image_name'])
-            with open("/root/result.json", 'w') as result:
-                res = {"notebook_image_name": image_conf['full_image_name'],
-                       "status": "terminated",
-                       "Action": "Delete existing notebook image"}
-                result.write(json.dumps(res))
+            GCPActions.remove_image(image_conf['expected_primary_image_name'])
+            GCPActions.remove_image(image_conf['expected_secondary_image_name'])
+        with open("/root/result.json", 'w') as result:
+            res = {"notebook_image_name": image_conf['expected_primary_image_name'],
+                   "endpoint": image_conf['endpoint_name'],
+                   "project": image_conf['project_name'],
+                   "imageName": image_conf['image_name'],
+                   "status": "terminated",
+                   "Action": "Delete existing notebook image"}
+            result.write(json.dumps(res))
 
     except Exception as err:
         datalab.fab.append_result("Failed to delete existing notebook image", str(err))
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/dataengine-service_create.py b/infrastructure-provisioning/src/general/scripts/gcp/dataengine-service_create.py
index 978d2d4..2ea506d 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/dataengine-service_create.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/dataengine-service_create.py
@@ -81,4 +81,4 @@
     build_dataproc_cluster(args, cluster_name)
     send_parser_job(args, cluster_name, cluster_version)
 
-    sys.exit(0)
\ No newline at end of file
+    sys.exit(0)
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/dataengine-service_prepare.py b/infrastructure-provisioning/src/general/scripts/gcp/dataengine-service_prepare.py
index 5c8972d..399faa2 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/dataengine-service_prepare.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/dataengine-service_prepare.py
@@ -33,6 +33,12 @@
 import subprocess
 from Crypto.PublicKey import RSA
 from fabric import *
+import argparse
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--uuid', type=str, default='')
+parser.add_argument('--access_password', type=str, default='')
+args = parser.parse_args()
 
 if __name__ == "__main__":
     try:
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/dataengine_prepare.py b/infrastructure-provisioning/src/general/scripts/gcp/dataengine_prepare.py
index 84ee186..c9aface 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/dataengine_prepare.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/dataengine_prepare.py
@@ -97,6 +97,13 @@
         if os.environ['conf_os_family'] == 'redhat':
             initial_user = 'ec2-user'
             sudo_group = 'wheel'
+
+        data_engine['gcp_os_login_enabled'] = os.environ['gcp_os_login_enabled']
+        data_engine['gcp_block_project_ssh_keys'] = os.environ['gcp_block_project_ssh_keys']
+        if "gcp_wrapped_csek" in os.environ:
+            data_engine['gcp_wrapped_csek'] = os.environ['gcp_wrapped_csek']
+        else:
+            data_engine['gcp_wrapped_csek'] = ''
         data_engine['cluster_name'] = "{}-{}-{}-de-{}".format(data_engine['service_base_name'],
                                                               data_engine['project_name'],
                                                               data_engine['endpoint_name'],
@@ -188,15 +195,18 @@
         params = "--instance_name {0} --region {1} --zone {2} --vpc_name {3} --subnet_name {4} --instance_size {5} " \
                  "--ssh_key_path {6} --initial_user {7} --service_account_name {8} --image_name {9} " \
                  "--secondary_image_name {10} --instance_class {11} --primary_disk_size {12} " \
-                 "--secondary_disk_size {13} --gpu_accelerator_type {14} --gpu_accelerator_count {15} --network_tag {16} --cluster_name {17} " \
-                 "--labels '{18}' --service_base_name {19}". \
+                 "--secondary_disk_size {13} --gpu_accelerator_type {14} --gpu_accelerator_count {15} " \
+                 "--network_tag {16} --cluster_name {17} --labels '{18}' --service_base_name {19} " \
+                 "--os_login_enabled FALSE --block_project_ssh_keys {21} --rsa_encrypted_csek '{22}'". \
             format(data_engine['master_node_name'], data_engine['region'], data_engine['zone'], data_engine['vpc_name'],
                    data_engine['subnet_name'], data_engine['master_size'], data_engine['ssh_key_path'], initial_user,
                    data_engine['dataengine_service_account_name'], data_engine['primary_image_name'],
                    data_engine['secondary_image_name'], 'dataengine', data_engine['primary_disk_size'],
                    data_engine['secondary_disk_size'], data_engine['gpu_master_accelerator_type'],
                    data_engine['gpu_master_accelerator_count'], data_engine['network_tag'], data_engine['cluster_name'],
-                   json.dumps(data_engine['master_labels']), data_engine['service_base_name'])
+                   json.dumps(data_engine['master_labels']), data_engine['service_base_name'],
+                   data_engine['gcp_os_login_enabled'], data_engine['gcp_block_project_ssh_keys'],
+                   data_engine['gcp_wrapped_csek'])
         try:
             subprocess.run("~/scripts/{}.py {}".format('common_create_instance', params), shell=True, check=True)
         except:
@@ -214,8 +224,9 @@
             params = "--instance_name {0} --region {1} --zone {2} --vpc_name {3} --subnet_name {4} " \
                      "--instance_size {5} --ssh_key_path {6} --initial_user {7} --service_account_name {8} " \
                      "--image_name {9} --secondary_image_name {10} --instance_class {11} --primary_disk_size {12} " \
-                     "--secondary_disk_size {13} --gpu_accelerator_type {14} --gpu_accelerator_count {15} --network_tag {16} --cluster_name {17} " \
-                     "--labels '{18}' --service_base_name {19}". \
+                     "--secondary_disk_size {13} --gpu_accelerator_type {14} --gpu_accelerator_count {15} " \
+                     "--network_tag {16} --cluster_name {17} --labels '{18}' --service_base_name {19} " \
+                     "--os_login_enabled FALSE --block_project_ssh_keys {21} --rsa_encrypted_csek '{22}'". \
                 format(slave_name, data_engine['region'], data_engine['zone'],
                        data_engine['vpc_name'], data_engine['subnet_name'], data_engine['slave_size'],
                        data_engine['ssh_key_path'], initial_user, data_engine['dataengine_service_account_name'],
@@ -224,7 +235,8 @@
                        data_engine['secondary_disk_size'], data_engine['gpu_slave_accelerator_type'],
                        data_engine['gpu_slave_accelerator_count'], data_engine['network_tag'],
                        data_engine['cluster_name'], json.dumps(data_engine['slave_labels']),
-                       data_engine['service_base_name'])
+                       data_engine['service_base_name'], data_engine['gcp_os_login_enabled'],
+                       data_engine['gcp_block_project_ssh_keys'], data_engine['gcp_wrapped_csek'])
             try:
                 subprocess.run("~/scripts/{}.py {}".format('common_create_instance', params), shell=True, check=True)
             except:
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/dataengine_start.py b/infrastructure-provisioning/src/general/scripts/gcp/dataengine_start.py
index 865d846..daef908 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/dataengine_start.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/dataengine_start.py
@@ -39,7 +39,7 @@
         instances = GCPMeta.get_list_instances(zone, cluster_name)
         if 'items' in instances:
             for i in instances['items']:
-                GCPActions.start_instance(i['name'], zone)
+                GCPActions.start_instance(i['name'], zone, data_engine['gcp_wrapped_csek'])
     except Exception as err:
         datalab.fab.append_result("Failed to start dataengine", str(err))
         sys.exit(1)
@@ -68,6 +68,10 @@
                                                           data_engine['project_name'],
                                                           data_engine['endpoint_name'],
                                                           data_engine['computational_name'])
+    if "gcp_wrapped_csek" in os.environ:
+        data_engine['gcp_wrapped_csek'] = os.environ['gcp_wrapped_csek']
+    else:
+        data_engine['gcp_wrapped_csek'] = ''
     try:
         logging.info('[STARTING DATA ENGINE]')
         try:
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/deeplearning_configure.py b/infrastructure-provisioning/src/general/scripts/gcp/deeplearning_configure.py
index be615de..f5c294b 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/deeplearning_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/deeplearning_configure.py
@@ -85,6 +85,11 @@
         notebook_config['datalab_ssh_user'] = os.environ['conf_os_user']
         notebook_config['zone'] = os.environ['gcp_zone']
         notebook_config['shared_image_enabled'] = os.environ['conf_shared_image_enabled']
+        if "gcp_wrapped_csek" in os.environ:
+            notebook_config['gcp_wrapped_csek'] = os.environ['gcp_wrapped_csek']
+        else:
+            notebook_config['gcp_wrapped_csek'] = ''
+
     except Exception as err:
         datalab.fab.append_result("Failed to generate variables dictionary", str(err))
         GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
@@ -208,7 +213,8 @@
                 logging.info("Looks like it's first time we configure notebook server. Creating images.")
                 image_id_list = GCPActions.create_image_from_instance_disks(
                     notebook_config['expected_primary_image_name'], notebook_config['expected_secondary_image_name'],
-                    notebook_config['instance_name'], notebook_config['zone'], notebook_config['image_labels'])
+                    notebook_config['instance_name'], notebook_config['zone'], notebook_config['image_labels'],
+                    notebook_config['gcp_wrapped_csek'])
                 if image_id_list and image_id_list[0] != '':
                     logging.info("Image of primary disk was successfully created. It's ID is {}".format(image_id_list[0]))
                 else:
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/edge_start.py b/infrastructure-provisioning/src/general/scripts/gcp/edge_start.py
index 2d35732..8dea7b6 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/edge_start.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/edge_start.py
@@ -45,10 +45,14 @@
     edge_conf['static_address_name'] = '{0}-{1}-{2}-static-ip'.format(edge_conf['service_base_name'],
                                                                edge_conf['project_name'],
                                                                edge_conf['endpoint_name'])
+    if "gcp_wrapped_csek" in os.environ:
+        edge_conf['gcp_wrapped_csek'] = os.environ['gcp_wrapped_csek']
+    else:
+        edge_conf['gcp_wrapped_csek'] = ''
 
     logging.info('[START EDGE]')
     try:
-        GCPActions.start_instance(edge_conf['instance_name'], edge_conf['zone'])
+        GCPActions.start_instance(edge_conf['instance_name'], edge_conf['zone'], edge_conf['gcp_wrapped_csek'])
     except Exception as err:
         datalab.fab.append_result("Failed to start edge.", str(err))
         sys.exit(1)
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/jupyter-gpu_configure.py b/infrastructure-provisioning/src/general/scripts/gcp/jupyter-gpu_configure.py
new file mode 100644
index 0000000..7c13d08
--- /dev/null
+++ b/infrastructure-provisioning/src/general/scripts/gcp/jupyter-gpu_configure.py
@@ -0,0 +1,362 @@
+#!/usr/bin/python3
+
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+import datalab.fab
+import datalab.actions_lib
+import datalab.meta_lib
+import json
+from datalab.logger import logging
+import os
+import sys
+import traceback
+import subprocess
+from fabric import *
+import uuid
+
+if __name__ == "__main__":
+    try:
+        GCPMeta = datalab.meta_lib.GCPMeta()
+        GCPActions = datalab.actions_lib.GCPActions()
+        notebook_config = dict()
+        try:
+            notebook_config['exploratory_name'] = (os.environ['exploratory_name']).replace('_', '-').lower()
+        except:
+            notebook_config['exploratory_name'] = ''
+        notebook_config['service_base_name'] = (os.environ['conf_service_base_name'])
+        notebook_config['instance_type'] = os.environ['gcp_notebook_instance_size']
+        notebook_config['key_name'] = os.environ['conf_key_name']
+        notebook_config['edge_user_name'] = (os.environ['edge_user_name'])
+        notebook_config['project_name'] = (os.environ['project_name']).replace('_', '-').lower()
+        notebook_config['project_tag'] = notebook_config['project_name']
+        notebook_config['endpoint_name'] = (os.environ['endpoint_name']).replace('_', '-').lower()
+        notebook_config['endpoint_tag'] = notebook_config['endpoint_name']
+        notebook_config['instance_name'] = '{0}-{1}-{2}-nb-{3}'.format(notebook_config['service_base_name'],
+                                                                       notebook_config['project_name'],
+                                                                       notebook_config['endpoint_name'],
+                                                                       notebook_config['exploratory_name'])
+        notebook_config['image_enabled'] = os.environ['conf_image_enabled']
+        notebook_config['shared_image_enabled'] = os.environ['conf_shared_image_enabled']
+        if notebook_config['shared_image_enabled'] == 'false':
+            notebook_config['expected_primary_image_name'] = '{}-{}-{}-{}-primary-image'.format(
+                notebook_config['service_base_name'], notebook_config['project_name'], notebook_config['endpoint_name'],
+                os.environ['application'])
+            notebook_config['expected_secondary_image_name'] = '{}-{}-{}-{}-secondary-image'.format(
+                notebook_config['service_base_name'], notebook_config['project_name'], notebook_config['endpoint_name'],
+                os.environ['application'])
+            notebook_config['image_labels'] = {"sbn": notebook_config['service_base_name'],
+                                               "endpoint_tag": notebook_config['endpoint_tag'],
+                                               "project_tag": notebook_config['project_tag'],
+                                               os.environ['conf_billing_tag_key']: os.environ['conf_billing_tag_value']}
+        else:
+            notebook_config['expected_primary_image_name'] = '{}-{}-{}-primary-image'.format(
+                notebook_config['service_base_name'], notebook_config['endpoint_name'], os.environ['application'])
+            notebook_config['expected_secondary_image_name'] = '{}-{}-{}-secondary-image'.format(
+                notebook_config['service_base_name'], notebook_config['endpoint_name'], os.environ['application'])
+            notebook_config['image_labels'] = {"sbn": notebook_config['service_base_name'],
+                                               "endpoint_tag": notebook_config['endpoint_tag'],
+                                               os.environ['conf_billing_tag_key']: os.environ['conf_billing_tag_value']}
+        # generating variables regarding EDGE proxy on Notebook instance
+        instance_hostname = GCPMeta.get_private_ip_address(notebook_config['instance_name'])
+        edge_instance_name = '{0}-{1}-{2}-edge'.format(notebook_config['service_base_name'],
+                                                       notebook_config['project_name'],
+                                                       notebook_config['endpoint_name'])
+        edge_instance_hostname = GCPMeta.get_instance_public_ip_by_name(edge_instance_name)
+        edge_instance_private_ip = GCPMeta.get_private_ip_address(edge_instance_name)
+        notebook_config['ssh_key_path'] = '{0}{1}.pem'.format(os.environ['conf_key_dir'], os.environ['conf_key_name'])
+        notebook_config['datalab_ssh_user'] = os.environ['conf_os_user']
+        notebook_config['zone'] = os.environ['gcp_zone']
+        notebook_config['shared_image_enabled'] = os.environ['conf_shared_image_enabled']
+        if "gcp_wrapped_csek" in os.environ:
+            notebook_config['gcp_wrapped_csek'] = os.environ['gcp_wrapped_csek']
+        else:
+            notebook_config['gcp_wrapped_csek'] = ''
+    except Exception as err:
+        datalab.fab.append_result("Failed to generate variables dictionary", str(err))
+        GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
+        sys.exit(1)
+
+    try:
+        if os.environ['conf_os_family'] == 'debian':
+            notebook_config['initial_user'] = 'ubuntu'
+            notebook_config['sudo_group'] = 'sudo'
+        if os.environ['conf_os_family'] == 'redhat':
+            notebook_config['initial_user'] = 'ec2-user'
+            notebook_config['sudo_group'] = 'wheel'
+
+        logging.info('[CREATING DATALAB SSH USER]')
+        params = "--hostname {} --keyfile {} --initial_user {} --os_user {} --sudo_group {}".format(
+            instance_hostname, notebook_config['ssh_key_path'], notebook_config['initial_user'],
+            notebook_config['datalab_ssh_user'], notebook_config['sudo_group'])
+
+        try:
+            subprocess.run("~/scripts/{}.py {}".format('create_ssh_user', params), shell=True, check=True)
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        datalab.fab.append_result("Failed creating ssh user 'datalab'.", str(err))
+        GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
+        sys.exit(1)
+
+    # configuring proxy on Notebook instance
+    try:
+        logging.info('[CONFIGURE PROXY ON JUPYTER INSTANCE]')
+        additional_config = {"proxy_host": edge_instance_name, "proxy_port": "3128"}
+        params = "--hostname {} --instance_name {} --keyfile {} --additional_config '{}' --os_user {}"\
+            .format(instance_hostname, notebook_config['instance_name'], notebook_config['ssh_key_path'],
+                    json.dumps(additional_config), notebook_config['datalab_ssh_user'])
+        try:
+            subprocess.run("~/scripts/{}.py {}".format('common_configure_proxy', params), shell=True, check=True)
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        datalab.fab.append_result("Failed to configure proxy.", str(err))
+        GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
+        sys.exit(1)
+
+    # updating repositories & installing python packages
+    try:
+        logging.info('[INSTALLING PREREQUISITES TO JUPYTER NOTEBOOK INSTANCE]')
+        params = "--hostname {} --keyfile {} --user {} --region {} --edge_private_ip {}". \
+            format(instance_hostname, notebook_config['ssh_key_path'], notebook_config['datalab_ssh_user'],
+                   os.environ['gcp_region'], edge_instance_private_ip)
+        try:
+            subprocess.run("~/scripts/{}.py {}".format('install_prerequisites', params), shell=True, check=True)
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        datalab.fab.append_result("Failed installing apps: apt & pip.", str(err))
+        GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
+        sys.exit(1)
+
+    # installing and configuring jupiter and all dependencies
+    try:
+        logging.info('[CONFIGURE JUPYTER NOTEBOOK INSTANCE]')
+        params = "--hostname {} --keyfile {} " \
+                 "--region {} --spark_version {} " \
+                 "--hadoop_version {} --os_user {} " \
+                 "--scala_version {} " \
+                 "--exploratory_name {} "\
+                 "--edge_ip {}".\
+            format(instance_hostname, notebook_config['ssh_key_path'],
+                   os.environ['gcp_region'], os.environ['notebook_spark_version'],
+                   os.environ['notebook_hadoop_version'], notebook_config['datalab_ssh_user'],
+                   os.environ['notebook_scala_version'],
+                   notebook_config['exploratory_name'], edge_instance_private_ip)
+        try:
+            subprocess.run("~/scripts/{}.py {}".format('configure_jupyter-gpu_node', params), shell=True, check=True)
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        datalab.fab.append_result("Failed to configure jupyter.", str(err))
+        GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
+        sys.exit(1)
+
+    try:
+        logging.info('[INSTALLING USERs KEY]')
+        additional_config = {"user_keyname": os.environ['project_name'],
+                             "user_keydir": os.environ['conf_key_dir']}
+        params = "--hostname {} --keyfile {} --additional_config '{}' --user {}".format(
+            instance_hostname, notebook_config['ssh_key_path'], json.dumps(additional_config),
+            notebook_config['datalab_ssh_user'])
+        try:
+            subprocess.run("~/scripts/{}.py {}".format('install_user_key', params), shell=True, check=True)
+        except:
+            datalab.fab.append_result("Failed installing users key")
+            raise Exception
+    except Exception as err:
+        datalab.fab.append_result("Failed installing users key.", str(err))
+        GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
+        sys.exit(1)
+
+    try:
+        logging.info('[SETUP USER GIT CREDENTIALS]')
+        params = '--os_user {} --notebook_ip {} --keyfile "{}"' \
+            .format(notebook_config['datalab_ssh_user'], instance_hostname, notebook_config['ssh_key_path'])
+        try:
+            subprocess.run("~/scripts/{}.py {}".format('common_download_git_certfile', params), shell=True, check=True)
+            subprocess.run("~/scripts/{}.py {}".format('manage_git_creds', params), shell=True, check=True)
+        except:
+            datalab.fab.append_result("Failed setup git credentials")
+            raise Exception
+    except Exception as err:
+        datalab.fab.append_result("Failed to setup git credentials.", str(err))
+        GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
+        sys.exit(1)
+
+    # installing gpu
+    try:
+        logging.info('[INSTALLING GPU DRIVERS]')
+        params = "--hostname {} --keyfile {} --os_user {}".format(
+            instance_hostname, notebook_config['ssh_key_path'], notebook_config['datalab_ssh_user'])
+        try:
+            subprocess.run("~/scripts/{}.py {}".format('common_install_gpu', params), shell=True, check=True)
+        except:
+            datalab.fab.append_result("Failed installing gpu drivers")
+            raise Exception
+
+    except Exception as err:
+        datalab.fab.append_result("Failed to install GPU drivers.", str(err))
+        GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
+        sys.exit(1)
+
+    if os.environ['notebook_create_keycloak_client'] == 'True':
+        try:
+            logging.info('[SETUP KEYCLOAK CLIENT]')
+            notebook_config['keycloak_client_name'] = '{}-{}-{}-{}'\
+                .format(notebook_config['service_base_name'], notebook_config['project_name'],
+                        notebook_config['endpoint_name'], notebook_config['exploratory_name'])
+            notebook_config['keycloak_client_secret'] = str(uuid.uuid4())
+            keycloak_params = "--service_base_name {} --keycloak_auth_server_url {} --keycloak_realm_name {} " \
+                              "--keycloak_user {} --keycloak_user_password {} --keycloak_client_secret {} " \
+                              "--project_name {} --endpoint_name {} --exploratory_name {}"\
+                .format(notebook_config['service_base_name'], os.environ['keycloak_auth_server_url'],
+                        os.environ['keycloak_realm_name'], os.environ['keycloak_user'],
+                        os.environ['keycloak_user_password'], notebook_config['keycloak_client_secret'],
+                        notebook_config['project_name'], notebook_config['endpoint_name'],
+                        notebook_config['exploratory_name'])
+            try:
+                subprocess.run("~/scripts/{}.py {}".format('configure_keycloak', keycloak_params), shell=True, check=True)
+            except:
+                datalab.fab.append_result("Failed setup keycloak client")
+                raise Exception
+
+            try:
+                conn = datalab.fab.init_datalab_connection(instance_hostname, notebook_config['datalab_ssh_user'],
+                                                           notebook_config['ssh_key_path'], '', False)
+                content = json.loads(conn.sudo("cat /home/{}/.local/share/jupyter/kernels/py3spark_local/kernel.json"
+                                               .format(notebook_config['datalab_ssh_user'])).stdout)
+                content['env']['KEYCLOAK_CLIENT'] = notebook_config['keycloak_client_name']
+                content['env']['KEYCLOAK_SECRET'] = notebook_config['keycloak_client_secret']
+                conn.sudo("echo '{}' > /home/{}/.local/share/jupyter/kernels/py3spark_local/kernel.json"
+                          .format(json.dumps(content), notebook_config['datalab_ssh_user']))
+                conn.sudo('systemctl restart jupyter-notebook')
+            except:
+                datalab.fab.append_result("Failed to write variables to .bashrc")
+                raise Exception
+
+        except Exception as err:
+            datalab.fab.append_result("Failed setup keycloak client ", str(err))
+            GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
+            sys.exit(1)
+
+    if notebook_config['image_enabled'] == 'true':
+        try:
+            logging.info('[CREATING IMAGE]')
+            primary_image_id = GCPMeta.get_image_by_name(notebook_config['expected_primary_image_name'])
+            if primary_image_id == '':
+                logging.info("Looks like it's first time we configure notebook server. Creating images.")
+                image_id_list = GCPActions.create_image_from_instance_disks(
+                    notebook_config['expected_primary_image_name'], notebook_config['expected_secondary_image_name'],
+                    notebook_config['instance_name'], notebook_config['zone'], notebook_config['image_labels'],
+                    notebook_config['gcp_wrapped_csek'])
+                if image_id_list and image_id_list[0] != '':
+                    logging.info("Image of primary disk was successfully created. It's ID is {}".format(image_id_list[0]))
+                else:
+                    logging.info("Looks like another image creating operation for your template have been started a "
+                          "moment ago.")
+                if image_id_list and image_id_list[1] != '':
+                    logging.info("Image of secondary disk was successfully created. It's ID is {}".format(image_id_list[1]))
+        except Exception as err:
+            datalab.fab.append_result("Failed creating image.", str(err))
+            GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
+            GCPActions.remove_image(notebook_config['expected_primary_image_name'])
+            GCPActions.remove_image(notebook_config['expected_secondary_image_name'])
+            sys.exit(1)
+
+
+    try:
+        logging.info('[SETUP EDGE REVERSE PROXY TEMPLATE]')
+        additional_info = {
+            'instance_hostname': instance_hostname,
+            'tensor': False
+        }
+        params = "--edge_hostname {} " \
+                 "--keyfile {} " \
+                 "--os_user {} " \
+                 "--type {} " \
+                 "--exploratory_name {} " \
+                 "--additional_info '{}'"\
+            .format(edge_instance_hostname,
+                    notebook_config['ssh_key_path'],
+                    notebook_config['datalab_ssh_user'],
+                    'jupyter-gpu',
+                    notebook_config['exploratory_name'],
+                    json.dumps(additional_info))
+        try:
+            subprocess.run("~/scripts/{}.py {}".format('common_configure_reverse_proxy', params), shell=True, check=True)
+        except:
+            datalab.fab.append_result("Failed edge reverse proxy template")
+            raise Exception
+    except Exception as err:
+        datalab.fab.append_result("Failed to set edge reverse proxy template.", str(err))
+        GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
+        sys.exit(1)
+
+    try:
+        # generating output information
+        ip_address = GCPMeta.get_private_ip_address(notebook_config['instance_name'])
+        jupyter_ip_url = "http://" + ip_address + ":8888/{}/".format(notebook_config['exploratory_name'])
+        ungit_ip_url = "http://" + ip_address + ":8085/{}-ungit/".format(notebook_config['exploratory_name'])
+        jupyter_notebook_access_url = "https://" + edge_instance_hostname + "/{}/".format(
+            notebook_config['exploratory_name'])
+        jupyter_ungit_access_url = "https://" + edge_instance_hostname + "/{}-ungit/".format(
+            notebook_config['exploratory_name'])
+        logging.info('[SUMMARY]')
+        logging.info("Instance name: {}".format(notebook_config['instance_name']))
+        logging.info("Private IP: {}".format(ip_address))
+        logging.info("Instance type: {}".format(notebook_config['instance_type']))
+        logging.info("Key name: {}".format(notebook_config['key_name']))
+        logging.info("User key name: {}".format(os.environ['project_name']))
+        logging.info("Jupyter URL: {}".format(jupyter_ip_url))
+        logging.info("Ungit URL: {}".format(ungit_ip_url))
+        logging.info("ReverseProxyNotebook".format(jupyter_notebook_access_url))
+        logging.info("ReverseProxyUngit".format(jupyter_ungit_access_url))
+        logging.info('SSH access (from Edge node, via IP address): ssh -i {0}.pem {1}@{2}'.format(
+            notebook_config['key_name'], notebook_config['datalab_ssh_user'], ip_address))
+
+        with open("/root/result.json", 'w') as result:
+            res = {"hostname": ip_address,
+                   "ip": ip_address,
+                   "instance_id": notebook_config['instance_name'],
+                   "master_keyname": os.environ['conf_key_name'],
+                   "notebook_name": notebook_config['instance_name'],
+                   "Action": "Create new notebook server",
+                   "exploratory_url": [
+                       {"description": "Jupyter",
+                        "url": jupyter_notebook_access_url},
+                       {"description": "Ungit",
+                        "url": jupyter_ungit_access_url}#,
+                       #{"description": "Jupyter (via tunnel)",
+                       # "url": jupyter_ip_url},
+                       #{"description": "Ungit (via tunnel)",
+                       # "url": ungit_ip_url}
+                   ]}
+            result.write(json.dumps(res))
+    except Exception as err:
+        datalab.fab.append_result("Failed to generate output information", str(err))
+        GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
+        sys.exit(1)
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/jupyter_configure.py b/infrastructure-provisioning/src/general/scripts/gcp/jupyter_configure.py
index 9a85703..17e3007 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/jupyter_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/jupyter_configure.py
@@ -31,6 +31,7 @@
 import traceback
 import subprocess
 from fabric import *
+import uuid
 
 if __name__ == "__main__":
     try:
@@ -85,6 +86,10 @@
         notebook_config['datalab_ssh_user'] = os.environ['conf_os_user']
         notebook_config['zone'] = os.environ['gcp_zone']
         notebook_config['shared_image_enabled'] = os.environ['conf_shared_image_enabled']
+        if "gcp_wrapped_csek" in os.environ:
+            notebook_config['gcp_wrapped_csek'] = os.environ['gcp_wrapped_csek']
+        else:
+            notebook_config['gcp_wrapped_csek'] = ''
     except Exception as err:
         datalab.fab.append_result("Failed to generate variables dictionary", str(err))
         GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
@@ -210,7 +215,8 @@
                 logging.info("Looks like it's first time we configure notebook server. Creating images.")
                 image_id_list = GCPActions.create_image_from_instance_disks(
                     notebook_config['expected_primary_image_name'], notebook_config['expected_secondary_image_name'],
-                    notebook_config['instance_name'], notebook_config['zone'], notebook_config['image_labels'])
+                    notebook_config['instance_name'], notebook_config['zone'], notebook_config['image_labels'],
+                    notebook_config['gcp_wrapped_csek'])
                 if image_id_list and image_id_list[0] != '':
                     logging.info("Image of primary disk was successfully created. It's ID is {}".format(image_id_list[0]))
                 else:
@@ -225,6 +231,44 @@
             GCPActions.remove_image(notebook_config['expected_secondary_image_name'])
             sys.exit(1)
 
+    if os.environ['notebook_create_keycloak_client'] == 'True':
+        try:
+            logging.info('[SETUP KEYCLOAK CLIENT]')
+            notebook_config['keycloak_client_name'] = '{}-{}-{}-{}'\
+                .format(notebook_config['service_base_name'], notebook_config['project_name'],
+                        notebook_config['endpoint_name'], notebook_config['exploratory_name'])
+            notebook_config['keycloak_client_secret'] = str(uuid.uuid4())
+            keycloak_params = "--service_base_name {} --keycloak_auth_server_url {} --keycloak_realm_name {} " \
+                              "--keycloak_user {} --keycloak_user_password {} --keycloak_client_secret {} " \
+                              "--project_name {} --endpoint_name {} --exploratory_name {}"\
+                .format(notebook_config['service_base_name'], os.environ['keycloak_auth_server_url'],
+                        os.environ['keycloak_realm_name'], os.environ['keycloak_user'],
+                        os.environ['keycloak_user_password'], notebook_config['keycloak_client_secret'],
+                        notebook_config['project_name'], notebook_config['endpoint_name'],
+                        notebook_config['exploratory_name'])
+            try:
+                subprocess.run("~/scripts/{}.py {}".format('configure_keycloak', keycloak_params), shell=True, check=True)
+            except:
+                datalab.fab.append_result("Failed setup keycloak client")
+                raise Exception
+
+            try:
+                conn = datalab.fab.init_datalab_connection(instance_hostname, notebook_config['datalab_ssh_user'],
+                                                           notebook_config['ssh_key_path'], '', False)
+                content = json.loads(conn.sudo("cat /home/{}/.local/share/jupyter/kernels/py3spark_local/kernel.json"
+                                               .format(notebook_config['datalab_ssh_user'])).stdout)
+                content['env']['KEYCLOAK_CLIENT'] = notebook_config['keycloak_client_name']
+                content['env']['KEYCLOAK_SECRET'] = notebook_config['keycloak_client_secret']
+                conn.sudo("echo '{}' > /home/{}/.local/share/jupyter/kernels/py3spark_local/kernel.json"
+                          .format(json.dumps(content), notebook_config['datalab_ssh_user']))
+                conn.sudo('systemctl restart jupyter-notebook')
+            except:
+                datalab.fab.append_result("Failed to write variables to .bashrc")
+                raise Exception
+
+        except Exception as err:
+            datalab.fab.append_result("Failed setup keycloak client ", str(err))
+
     if os.environ['gpu_enabled'] == 'True':
         try:
             logging.info('[INSTALLING GPU DRIVERS]')
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/jupyter_install_dataengine-service_kernels.py b/infrastructure-provisioning/src/general/scripts/gcp/jupyter_install_dataengine-service_kernels.py
index 7fc3ae9..a209d90 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/jupyter_install_dataengine-service_kernels.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/jupyter_install_dataengine-service_kernels.py
@@ -63,7 +63,7 @@
     datalab.fab.conn.sudo('mkdir -p /usr/lib/python3.8/datalab/')
     datalab.fab.conn.run('mkdir -p /tmp/datalab_libs/')
     host_string = args.os_user + "@" + args.notebook_ip
-    datalab.fab.conn.local('scp -i {} /usr/lib/python3.8/datalab/*.py {}:/tmp/datalab_libs/'.format(args.keyfile, host_string))
+    datalab.fab.conn.local('rsync -e "ssh -i {}" /usr/lib/python3.8/datalab/*.py {}:/tmp/datalab_libs/'.format(args.keyfile, host_string))
     datalab.fab.conn.run('chmod a+x /tmp/datalab_libs/*')
     datalab.fab.conn.sudo('mv /tmp/datalab_libs/* /usr/lib/python3.8/datalab/')
     if exists(datalab.fab.conn, '/usr/lib64'):
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/jupyterlab_configure.py b/infrastructure-provisioning/src/general/scripts/gcp/jupyterlab_configure.py
index 100999a..2baa8ee 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/jupyterlab_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/jupyterlab_configure.py
@@ -85,6 +85,10 @@
         notebook_config['datalab_ssh_user'] = os.environ['conf_os_user']
         notebook_config['zone'] = os.environ['gcp_zone']
         notebook_config['shared_image_enabled'] = os.environ['conf_shared_image_enabled']
+        if "gcp_wrapped_csek" in os.environ:
+            notebook_config['gcp_wrapped_csek'] = os.environ['gcp_wrapped_csek']
+        else:
+            notebook_config['gcp_wrapped_csek'] = ''
     except Exception as err:
         datalab.fab.append_result("Failed to generate variables dictionary", str(err))
         GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
@@ -208,7 +212,8 @@
                 logging.info("Looks like it's first time we configure notebook server. Creating images.")
                 image_id_list = GCPActions.create_image_from_instance_disks(
                     notebook_config['expected_primary_image_name'], notebook_config['expected_secondary_image_name'],
-                    notebook_config['instance_name'], notebook_config['zone'], notebook_config['image_labels'])
+                    notebook_config['instance_name'], notebook_config['zone'], notebook_config['image_labels'],
+                    notebook_config['gcp_wrapped_csek'])
                 if image_id_list and image_id_list[0] != '':
                     logging.info("Image of primary disk was successfully created. It's ID is {}".format(image_id_list[0]))
                 else:
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/project_prepare.py b/infrastructure-provisioning/src/general/scripts/gcp/project_prepare.py
index d5a06c9..470fac4 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/project_prepare.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/project_prepare.py
@@ -121,6 +121,17 @@
         else:
             project_conf['user_subnets_range'] = ''
 
+        project_conf['gcp_bucket_enable_versioning'] = os.environ['conf_bucket_versioning_enabled']
+        if 'gcp_cmek_resource_name' in os.environ:
+            project_conf['gcp_cmek_resource_name'] = os.environ['gcp_cmek_resource_name']
+        else:
+            project_conf['gcp_cmek_resource_name'] = ''
+
+        if 'gcp_storage_lifecycle_rules' in os.environ:
+            project_conf['gcp_storage_lifecycle_rules'] = os.environ['gcp_storage_lifecycle_rules']
+        else:
+            project_conf['gcp_storage_lifecycle_rules'] = ''
+
         # FUSE in case of absence of user's key
         try:
             project_conf['user_key'] = os.environ['key']
@@ -399,8 +410,13 @@
             os.environ['conf_billing_tag_key']: os.environ['conf_billing_tag_value'],
             "sbn": project_conf['service_base_name'],
             "name": project_conf['shared_bucket_name']}
-        params = "--bucket_name {} --tags '{}'".format(project_conf['shared_bucket_name'],
-                                                       json.dumps(project_conf['shared_bucket_tags']))
+        params = "--bucket_name {} --tags '{}' --versioning_enabled {} --lifecycle_rules '{}'".format(
+            project_conf['shared_bucket_name'], json.dumps(project_conf['shared_bucket_tags']),
+            project_conf['gcp_bucket_enable_versioning'], json.dumps(project_conf['gcp_storage_lifecycle_rules']))
+
+        if project_conf['gcp_cmek_resource_name'] != '':
+            params = '{} --cmek_resource_name {}'.format(params, project_conf['gcp_cmek_resource_name'])
+
         try:
             subprocess.run("~/scripts/{}.py {}".format('common_create_bucket', params), shell=True, check=True)
         except:
@@ -414,8 +430,12 @@
             "sbn": project_conf['service_base_name'],
             "project_tag": project_conf['project_tag'],
             "name": project_conf['bucket_name']}
-        params = "--bucket_name {} --tags '{}'".format(project_conf['bucket_name'],
-                                                       json.dumps(project_conf['bucket_tags']))
+        params = "--bucket_name {} --tags '{}' --versioning_enabled {} --lifecycle_rules '{}'".format(
+            project_conf['bucket_name'], json.dumps(project_conf['bucket_tags']),
+            project_conf['gcp_bucket_enable_versioning'], json.dumps(project_conf['gcp_storage_lifecycle_rules']))
+
+        if project_conf['gcp_cmek_resource_name'] != '':
+            params = '{} --cmek_resource_name {}'.format(params, project_conf['gcp_cmek_resource_name'])
 
         try:
             subprocess.run("~/scripts/{}.py {}".format('common_create_bucket', params), shell=True, check=True)
@@ -500,18 +520,28 @@
         project_conf['initial_user'] = 'ec2-user'
         project_conf['sudo_group'] = 'wheel'
 
+    project_conf['gcp_os_login_enabled'] = os.environ['gcp_os_login_enabled']
+    project_conf['gcp_block_project_ssh_keys'] = os.environ['gcp_block_project_ssh_keys']
+    if "gcp_wrapped_csek" in os.environ:
+        project_conf['gcp_wrapped_csek'] = os.environ['gcp_wrapped_csek']
+    else:
+        project_conf['gcp_wrapped_csek'] = ''
+
     try:
         project_conf['static_ip'] = \
             GCPMeta.get_static_address(project_conf['region'], project_conf['static_address_name'])['address']
         logging.info('[CREATE EDGE INSTANCE]')
         params = "--instance_name {} --region {} --zone {} --vpc_name {} --subnet_name {} --instance_size {} " \
                  "--ssh_key_path {} --initial_user {} --service_account_name {} --image_name {} --instance_class {} " \
-                 "--static_ip {} --network_tag {} --labels '{}' --service_base_name {}".format(
+                 "--static_ip {} --network_tag {} --labels '{}' --service_base_name {} --os_login_enabled {} " \
+                 "--block_project_ssh_keys {} --rsa_encrypted_csek '{}'".format(
                   project_conf['instance_name'], project_conf['region'], project_conf['zone'], project_conf['vpc_name'],
                   project_conf['subnet_name'], project_conf['instance_size'], project_conf['ssh_key_path'],
                   project_conf['initial_user'], project_conf['edge_service_account_name'], project_conf['image_name'],
                   'edge', project_conf['static_ip'], project_conf['network_tag'],
-                  json.dumps(project_conf['instance_labels']), project_conf['service_base_name'])
+                  json.dumps(project_conf['instance_labels']), project_conf['service_base_name'],
+                  project_conf['gcp_os_login_enabled'], project_conf['gcp_block_project_ssh_keys'],
+                  project_conf['gcp_wrapped_csek'])
         try:
             subprocess.run("~/scripts/{}.py {}".format('common_create_instance', params), shell=True, check=True)
         except:
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/rstudio_configure.py b/infrastructure-provisioning/src/general/scripts/gcp/rstudio_configure.py
index dae62df..c5969ef 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/rstudio_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/rstudio_configure.py
@@ -88,6 +88,10 @@
         notebook_config['shared_image_enabled'] = os.environ['conf_shared_image_enabled']
         notebook_config['ip_address'] = GCPMeta.get_private_ip_address(notebook_config['instance_name'])
         notebook_config['rstudio_pass'] = datalab.fab.id_generator()
+        if "gcp_wrapped_csek" in os.environ:
+            notebook_config['gcp_wrapped_csek'] = os.environ['gcp_wrapped_csek']
+        else:
+            notebook_config['gcp_wrapped_csek'] = ''
     except Exception as err:
         datalab.fab.append_result("Failed to generate variables dictionary", str(err))
         GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
@@ -212,7 +216,8 @@
                 logging.info("Looks like it's first time we configure notebook server. Creating images.")
                 image_id_list = GCPActions.create_image_from_instance_disks(
                     notebook_config['expected_primary_image_name'], notebook_config['expected_secondary_image_name'],
-                    notebook_config['instance_name'], notebook_config['zone'], notebook_config['image_labels'])
+                    notebook_config['instance_name'], notebook_config['zone'], notebook_config['image_labels'],
+                    notebook_config['gcp_wrapped_csek'])
                 if image_id_list and image_id_list[0] != '':
                     logging.info("Image of primary disk was successfully created. It's ID is {}".format(image_id_list[0]))
                 else:
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/rstudio_install_dataengine-service_kernels.py b/infrastructure-provisioning/src/general/scripts/gcp/rstudio_install_dataengine-service_kernels.py
index be225cd..127b492 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/rstudio_install_dataengine-service_kernels.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/rstudio_install_dataengine-service_kernels.py
@@ -43,7 +43,6 @@
 parser.add_argument('--os_user', type=str, default='')
 parser.add_argument('--edge_hostname', type=str, default='')
 parser.add_argument('--proxy_port', type=str, default='')
-parser.add_argument('--pip_mirror', type=str, default='')
 parser.add_argument('--application', type=str, default='')
 args = parser.parse_args()
 
@@ -55,7 +54,7 @@
     conn.sudo('chmod 755 /usr/local/bin/create_configs.py')
     conn.sudo('mkdir -p /usr/lib/python3.8/datalab/')
     conn.run('mkdir -p /home/{}/datalab_libs/'.format(args.os_user))
-    conn.local('scp -i {0} /usr/lib/python3.8/datalab/*.py {1}@{2}:/home/{1}/datalab_libs/'.format(args.keyfile, args.os_user, args.notebook_ip))
+    conn.local('rsync -e "ssh -i {0}" /usr/lib/python3.8/datalab/*.py {1}@{2}:/home/{1}/datalab_libs/'.format(args.keyfile, args.os_user, args.notebook_ip))
     conn.run('chmod a+x /home/{}/datalab_libs/*'.format(args.os_user))
     conn.sudo('mv /home/{}/datalab_libs/* /usr/lib/python3.8/datalab/'.format(args.os_user))
     conn.sudo('rm -rf /home/{}/datalab_libs/'.format(args.os_user))
@@ -72,6 +71,6 @@
     hadoop_version = datalab.actions_lib.GCPActions().get_cluster_app_version(args.bucket, args.project_name, args.cluster_name, 'hadoop')
     conn.sudo('''bash -l -c 'echo "[global]" > /etc/pip.conf; echo "proxy = $(cat /etc/profile | grep proxy | head -n1 | cut -f2 -d=)" >> /etc/pip.conf' ''')
     conn.sudo('''bash -l -c 'echo "use_proxy=yes" > ~/.wgetrc; proxy=$(cat /etc/profile | grep proxy | head -n1 | cut -f2 -d=); echo "http_proxy=$proxy" >> ~/.wgetrc; echo "https_proxy=$proxy" >> ~/.wgetrc' ''')
-    conn.sudo('''bash -l -c 'unset http_proxy https_proxy; export gcp_project_id="{0}"; export conf_resource="{1}"; /usr/bin/python3 /usr/local/bin/create_configs.py --bucket {2} --cluster_name {3} --dataproc_version {4} --spark_version {5} --hadoop_version {6} --region {7} --user_name {8} --os_user {9} --pip_mirror {10} --application {11}' '''
+    conn.sudo('''bash -l -c 'unset http_proxy https_proxy; export gcp_project_id="{0}"; export conf_resource="{1}"; /usr/bin/python3 /usr/local/bin/create_configs.py --bucket {2} --cluster_name {3} --dataproc_version {4} --spark_version {5} --hadoop_version {6} --region {7} --user_name {8} --os_user {9} --application {10}' '''
          .format(os.environ['gcp_project_id'], os.environ['conf_resource'], args.bucket, args.cluster_name, args.dataproc_version, spark_version, hadoop_version,
-                 args.region, args.project_name, args.os_user, args.pip_mirror, args.application))
+                 args.region, args.project_name, args.os_user, args.application))
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/ssn_configure.py b/infrastructure-provisioning/src/general/scripts/gcp/ssn_configure.py
index d55fce0..dc55d17 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/ssn_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/ssn_configure.py
@@ -159,7 +159,7 @@
     try:
         logging.info('[INSTALLING PREREQUISITES TO SSN INSTANCE]')
         params = "--hostname {} --keyfile {} --pip_packages " \
-                 "'boto3 bcrypt==3.1.7 backoff argparse fabric awscli pymongo pyyaml " \
+                 "'boto3 bcrypt==3.1.7 cryptography==36.0.2 backoff argparse fabric awscli pymongo pyyaml " \
                  "google-api-python-client google-cloud-storage pycryptodome' --user {} --region {}". \
             format(ssn_conf['instance_hostname'], ssn_conf['ssh_key_path'],
                    ssn_conf['datalab_ssh_user'], ssn_conf['region'])
@@ -202,6 +202,7 @@
                              {"name": "project", "tag": "latest"},
                              {"name": "edge", "tag": "latest"},
                              {"name": "jupyter", "tag": "latest"},
+                             {"name": "jupyter-gpu", "tag": "latest"},
                              {"name": "jupyterlab", "tag": "latest"},
                              {"name": "rstudio", "tag": "latest"},
                              {"name": "zeppelin", "tag": "latest"},
@@ -501,14 +502,15 @@
         params = "--hostname {} --keyfile {} --datalab_path {} --os_user {} --os_family {} --billing_enabled {} " \
                  "--request_id {} --billing_dataset_name {} \
                  --resource {} --service_base_name {} --cloud_provider {} --default_endpoint_name {} " \
-                 "--cloud_params '{}' --keycloak_client_id {} --keycloak_client_secret {} --keycloak_auth_server_url {}". \
+                 "--cloud_params '{}' --keycloak_client_id {} --keycloak_client_secret {}" \
+                 " --keycloak_auth_server_url {} --keycloak_realm_name {}". \
             format(ssn_conf['instance_hostname'], ssn_conf['ssh_key_path'], os.environ['ssn_datalab_path'],
                    ssn_conf['datalab_ssh_user'],
                    os.environ['conf_os_family'], ssn_conf['billing_enabled'], os.environ['request_id'],
                    os.environ['billing_dataset_name'], os.environ['conf_resource'],
                    ssn_conf['service_base_name'], os.environ['conf_cloud_provider'], ssn_conf['default_endpoint_name'],
                    json.dumps(cloud_params), os.environ['keycloak_client_name'], os.environ['keycloak_client_secret'],
-                   os.environ['keycloak_auth_server_url'])
+                   os.environ['keycloak_auth_server_url'], os.environ['keycloak_realm_name'])
         try:
             subprocess.run("~/scripts/{}.py {}".format('configure_ui', params), shell=True, check=True)
         except:
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/ssn_prepare.py b/infrastructure-provisioning/src/general/scripts/gcp/ssn_prepare.py
index 59f0658..78d7621 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/ssn_prepare.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/ssn_prepare.py
@@ -71,6 +71,14 @@
                                        "sbn": ssn_conf['service_base_name'],
                                        os.environ['conf_billing_tag_key']: os.environ['conf_billing_tag_value']}
         ssn_conf['allowed_ip_cidr'] = os.environ['conf_allowed_ip_cidr']
+        ssn_conf['gcp_os_login_enabled'] = os.environ['gcp_os_login_enabled']
+        ssn_conf['gcp_block_project_ssh_keys'] = os.environ['gcp_block_project_ssh_keys']
+
+        if "gcp_wrapped_csek" in os.environ:
+            ssn_conf['gcp_wrapped_csek'] = os.environ['gcp_wrapped_csek']
+        else:
+            ssn_conf['gcp_wrapped_csek'] = ''
+
     except Exception as err:
         datalab.fab.append_result("Failed to generate variables dictionary.", str(err))
         sys.exit(1)
@@ -265,12 +273,14 @@
         params = "--instance_name {0} --region {1} --zone {2} --vpc_name {3} --subnet_name {4} --instance_size {5}"\
                  " --ssh_key_path {6} --initial_user {7} --service_account_name {8} --image_name {9}"\
                  " --instance_class {10} --static_ip {11} --network_tag {12} --labels '{13}' " \
-                 "--primary_disk_size {14} --service_base_name {15}".\
+                 "--primary_disk_size {14} --service_base_name {15} --os_login_enabled {16} " \
+                 "--block_project_ssh_keys {17} --rsa_encrypted_csek '{18}'".\
             format(ssn_conf['instance_name'], ssn_conf['region'], ssn_conf['zone'], ssn_conf['vpc_name'],
                    ssn_conf['subnet_name'], ssn_conf['instance_size'], ssn_conf['ssh_key_path'],
                    ssn_conf['initial_user'], ssn_conf['service_account_name'], ssn_conf['image_name'], 'ssn',
                    ssn_conf['static_ip'], ssn_conf['network_tag'], json.dumps(ssn_conf['instance_labels']), '20',
-                   ssn_conf['service_base_name'])
+                   ssn_conf['service_base_name'], ssn_conf['gcp_os_login_enabled'],
+                   ssn_conf['gcp_block_project_ssh_keys'], ssn_conf['gcp_wrapped_csek'])
         try:
             subprocess.run("~/scripts/{}.py {}".format('common_create_instance', params), shell=True, check=True)
         except:
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/ssn_terminate_gcp_resources.py b/infrastructure-provisioning/src/general/scripts/gcp/ssn_terminate_gcp_resources.py
index c0938f6..323498a 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/ssn_terminate_gcp_resources.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/ssn_terminate_gcp_resources.py
@@ -137,12 +137,15 @@
         sys.exit(1)
 
     logging.info("Removing SSN VPC")
-    if args.pre_defined_vpc != 'True':
-        try:
-            GCPActions.remove_vpc(args.vpc_name)
-        except Exception as err:
-            logging.error('Error: {0}'.format(err))
-            logging.error("No such VPC")
-            sys.exit(1)
-    else:
-        logging.info('VPC is predefined, VPC will not be deleted')
+    try:
+        vpc_list = GCPMeta.get_vpc(args.vpc_name)
+        if args.pre_defined_vpc != 'True':
+            if 'name' in vpc_list:
+                GCPActions.remove_vpc(args.vpc_name)
+            else:
+                logging.info("Unable to find {0}".format(args.vpc_name))
+        else:
+            logging.info('VPC is predefined, VPC will not be deleted')
+    except Exception as err:
+        logging.error('Error: {0}'.format(err))
+        sys.exit(1)
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/superset_configure.py b/infrastructure-provisioning/src/general/scripts/gcp/superset_configure.py
index 709a534..44295da 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/superset_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/superset_configure.py
@@ -87,6 +87,10 @@
         notebook_config['datalab_ssh_user'] = os.environ['conf_os_user']
         notebook_config['zone'] = os.environ['gcp_zone']
         notebook_config['shared_image_enabled'] = os.environ['conf_shared_image_enabled']
+        if "gcp_wrapped_csek" in os.environ:
+            notebook_config['gcp_wrapped_csek'] = os.environ['gcp_wrapped_csek']
+        else:
+            notebook_config['gcp_wrapped_csek'] = ''
     except Exception as err:
         datalab.fab.append_result("Failed to generate variables dictionary", str(err))
         GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
@@ -254,7 +258,8 @@
                 logging.info("Looks like it's first time we configure notebook server. Creating images.")
                 image_id_list = GCPActions.create_image_from_instance_disks(
                     notebook_config['expected_primary_image_name'], notebook_config['expected_secondary_image_name'],
-                    notebook_config['instance_name'], notebook_config['zone'], notebook_config['image_labels'])
+                    notebook_config['instance_name'], notebook_config['zone'], notebook_config['image_labels'],
+                    notebook_config['gcp_wrapped_csek'])
                 if image_id_list and image_id_list[0] != '':
                     logging.info("Image of primary disk was successfully created. It's ID is {}".format(image_id_list[0]))
                 else:
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/tensor-rstudio_configure.py b/infrastructure-provisioning/src/general/scripts/gcp/tensor-rstudio_configure.py
index a1a990d..423d444 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/tensor-rstudio_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/tensor-rstudio_configure.py
@@ -92,6 +92,10 @@
         notebook_config['zone'] = os.environ['gcp_zone']
         notebook_config['shared_image_enabled'] = os.environ['conf_shared_image_enabled']
         notebook_config['rstudio_pass'] = datalab.fab.id_generator()
+        if "gcp_wrapped_csek" in os.environ:
+            notebook_config['gcp_wrapped_csek'] = os.environ['gcp_wrapped_csek']
+        else:
+            notebook_config['gcp_wrapped_csek'] = ''
     except Exception as err:
         datalab.fab.append_result("Failed to generate variables dictionary", str(err))
         GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
@@ -214,7 +218,8 @@
                 logging.info("Looks like it's first time we configure notebook server. Creating images.")
                 image_id_list = GCPActions.create_image_from_instance_disks(
                     notebook_config['expected_primary_image_name'], notebook_config['expected_secondary_image_name'],
-                    notebook_config['instance_name'], notebook_config['zone'], notebook_config['image_labels'])
+                    notebook_config['instance_name'], notebook_config['zone'], notebook_config['image_labels'],
+                    notebook_config['gcp_wrapped_csek'])
                 if image_id_list and image_id_list[0] != '':
                     logging.info("Image of primary disk was successfully created. It's ID is {}".format(image_id_list[0]))
                 else:
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/tensor_configure.py b/infrastructure-provisioning/src/general/scripts/gcp/tensor_configure.py
index dd67bfa..9a4557b 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/tensor_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/tensor_configure.py
@@ -86,6 +86,10 @@
         notebook_config['datalab_ssh_user'] = os.environ['conf_os_user']
         notebook_config['zone'] = os.environ['gcp_zone']
         notebook_config['shared_image_enabled'] = os.environ['conf_shared_image_enabled']
+        if "gcp_wrapped_csek" in os.environ:
+            notebook_config['gcp_wrapped_csek'] = os.environ['gcp_wrapped_csek']
+        else:
+            notebook_config['gcp_wrapped_csek'] = ''
     except Exception as err:
         datalab.fab.append_result("Failed to generate variables dictionary", str(err))
         GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
@@ -219,7 +223,8 @@
                 logging.info("Looks like it's first time we configure notebook server. Creating images.")
                 image_id_list = GCPActions.create_image_from_instance_disks(
                     notebook_config['expected_primary_image_name'], notebook_config['expected_secondary_image_name'],
-                    notebook_config['instance_name'], notebook_config['zone'], notebook_config['image_labels'])
+                    notebook_config['instance_name'], notebook_config['zone'], notebook_config['image_labels'],
+                    notebook_config['gcp_wrapped_csek'])
                 if image_id_list and image_id_list[0] != '':
                     logging.info("Image of primary disk was successfully created. It's ID is {}".format(image_id_list[0]))
                 else:
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/zeppelin_configure.py b/infrastructure-provisioning/src/general/scripts/gcp/zeppelin_configure.py
index 78a96a1..00422ea 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/zeppelin_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/zeppelin_configure.py
@@ -86,6 +86,10 @@
         notebook_config['datalab_ssh_user'] = os.environ['conf_os_user']
         notebook_config['zone'] = os.environ['gcp_zone']
         notebook_config['shared_image_enabled'] = os.environ['conf_shared_image_enabled']
+        if "gcp_wrapped_csek" in os.environ:
+            notebook_config['gcp_wrapped_csek'] = os.environ['gcp_wrapped_csek']
+        else:
+            notebook_config['gcp_wrapped_csek'] = ''
     except Exception as err:
         datalab.fab.append_result("Failed to generate variables dictionary", str(err))
         GCPActions.remove_instance(notebook_config['instance_name'], notebook_config['zone'])
@@ -219,7 +223,8 @@
                 logging.info("Looks like it's first time we configure notebook server. Creating images.")
                 image_id_list = GCPActions.create_image_from_instance_disks(
                     notebook_config['expected_primary_image_name'], notebook_config['expected_secondary_image_name'],
-                    notebook_config['instance_name'], notebook_config['zone'], notebook_config['image_labels'])
+                    notebook_config['instance_name'], notebook_config['zone'], notebook_config['image_labels'],
+                    notebook_config['gcp_wrapped_csek'])
                 if image_id_list and image_id_list[0] != '':
                     logging.info("Image of primary disk was successfully created. It's ID is {}".format(image_id_list[0]))
                 else:
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/zeppelin_dataengine-service_create_configs.py b/infrastructure-provisioning/src/general/scripts/gcp/zeppelin_dataengine-service_create_configs.py
index ea33688..380015c 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/zeppelin_dataengine-service_create_configs.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/zeppelin_dataengine-service_create_configs.py
@@ -36,6 +36,7 @@
 parser.add_argument('--dataproc_version', type=str, default='')
 parser.add_argument('--spark_version', type=str, default='')
 parser.add_argument('--hadoop_version', type=str, default='')
+parser.add_argument('--numpy_version', type=str, default='')
 parser.add_argument('--region', type=str, default='')
 parser.add_argument('--user_name', type=str, default='')
 parser.add_argument('--os_user', type=str, default='')
@@ -80,7 +81,11 @@
         configuring_notebook(args.dataproc_version)
         if args.multiple_clusters == 'true':
             install_remote_livy(args)
-        installing_python(args.region, args.bucket, args.user_name, args.cluster_name, args.application, args.pip_mirror)
-        datalab.actions_lib.GCPActions().configure_zeppelin_dataproc_interpreter(args.dataproc_version, args.cluster_name, spark_dir, args.os_user,
-                                                                         yarn_dir, args.bucket, args.user_name, args.multiple_clusters)
+        installing_python(args.region, args.bucket, args.user_name, args.cluster_name, args.application,
+                          args.pip_mirror, args.numpy_version)
+        datalab.actions_lib.GCPActions().configure_zeppelin_dataproc_interpreter(args.dataproc_version,
+                                                                                 args.cluster_name, spark_dir,
+                                                                                 args.os_user, yarn_dir,
+                                                                                 args.bucket, args.user_name,
+                                                                                 args.multiple_clusters)
         update_zeppelin_interpreters(args.multiple_clusters, args.r_enabled)
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/zeppelin_install_dataengine-service_kernels.py b/infrastructure-provisioning/src/general/scripts/gcp/zeppelin_install_dataengine-service_kernels.py
index 8269b93..7893d64 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/zeppelin_install_dataengine-service_kernels.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/zeppelin_install_dataengine-service_kernels.py
@@ -41,7 +41,6 @@
 parser.add_argument('--os_user', type=str, default='')
 parser.add_argument('--edge_hostname', type=str, default='')
 parser.add_argument('--proxy_port', type=str, default='')
-parser.add_argument('--pip_mirror', type=str, default='')
 parser.add_argument('--application', type=str, default='')
 args = parser.parse_args()
 
@@ -58,7 +57,8 @@
     conn.sudo('chmod 755 /usr/local/bin/create_configs.py')
     conn.sudo('mkdir -p /usr/lib/python3.8/datalab/')
     conn.run('mkdir -p /home/{}/datalab_libs/'.format(args.os_user))
-    conn.local('scp -i {0} /usr/lib/python3.8/datalab/*.py {1}@{2}:/home/{1}/datalab_libs/'.format(args.keyfile, args.os_user, args.notebook_ip))
+    conn.local('rsync -e "ssh -i {0}" /usr/lib/python3.8/datalab/*.py {1}@{2}:/home/{1}/datalab_libs/'
+               .format(args.keyfile, args.os_user, args.notebook_ip))
     conn.run('chmod a+x /home/{}/datalab_libs/*'.format(args.os_user))
     conn.sudo('mv /home/{}/datalab_libs/* /usr/lib/python3.8/datalab/'.format(args.os_user))
     conn.sudo('rm -rf /home/{}/datalab_libs/'.format(args.os_user))
@@ -76,7 +76,8 @@
     hadoop_version = datalab.actions_lib.GCPActions().get_cluster_app_version(args.bucket, args.project_name, args.cluster_name, 'hadoop')
     conn.sudo('''bash -l -c 'echo "[global]" > /etc/pip.conf; echo "proxy = $(cat /etc/profile | grep proxy | head -n1 | cut -f2 -d=)" >> /etc/pip.conf' ''')
     conn.sudo('''bash -l -c 'echo "use_proxy=yes" > ~/.wgetrc; proxy=$(cat /etc/profile | grep proxy | head -n1 | cut -f2 -d=); echo "http_proxy=$proxy" >> ~/.wgetrc; echo "https_proxy=$proxy" >> ~/.wgetrc' ''')
-    conn.sudo('''bash -l -c 'unset http_proxy https_proxy; export gcp_project_id="{0}"; export conf_resource="{1}"; /usr/bin/python3 /usr/local/bin/create_configs.py --bucket {2} --cluster_name {3} --dataproc_version {4} --spark_version {5} --hadoop_version {6} --region {7} --user_name {8} --os_user {9} --pip_mirror {10} --application {11} --livy_version {12} --multiple_clusters {13} --r_enabled {14}' '''
-        .format(os.environ['gcp_project_id'], os.environ['conf_resource'], args.bucket, args.cluster_name, args.dataproc_version,
-                spark_version, hadoop_version, args.region, args.project_name, args.os_user, args.pip_mirror, args.application,
-                os.environ['notebook_livy_version'], os.environ['notebook_multiple_clusters'], r_enabled))
\ No newline at end of file
+    conn.sudo('''bash -l -c 'unset http_proxy https_proxy; export gcp_project_id="{0}"; export conf_resource="{1}"; /usr/bin/python3 /usr/local/bin/create_configs.py --bucket {2} --cluster_name {3} --dataproc_version {4} --spark_version {5} --hadoop_version {6} --region {7} --user_name {8} --os_user {9} --application {10} --livy_version {11} --multiple_clusters {12} --r_enabled {13} --numpy_version {14}' '''
+        .format(os.environ['gcp_project_id'], os.environ['conf_resource'], args.bucket, args.cluster_name,
+                args.dataproc_version, spark_version, hadoop_version, args.region, args.project_name, args.os_user,
+                args.application, os.environ['notebook_livy_version'], os.environ['notebook_multiple_clusters'],
+                r_enabled, os.environ['notebook_numpy_version']))
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/general/scripts/os/common_clean_instance.py b/infrastructure-provisioning/src/general/scripts/os/common_clean_instance.py
index 548e931..79049df 100644
--- a/infrastructure-provisioning/src/general/scripts/os/common_clean_instance.py
+++ b/infrastructure-provisioning/src/general/scripts/os/common_clean_instance.py
@@ -67,6 +67,20 @@
         print('Error: {0}'.format(err))
         sys.exit(1)
 
+def clean_jupyterlab():
+    try:
+        conn.sudo('systemctl stop jupyterlab-notebook')
+        conn.sudo('pip3 uninstall -y jupyterlab')
+        #conn.sudo('rm -rf /usr/local/share/jupyter/')
+        conn.sudo('rm -rf /home/{}/.jupyter/'.format(args.os_user))
+        conn.sudo('rm -rf /home/{}/.ipython/'.format(args.os_user))
+        conn.sudo('rm -rf /home/{}/.ipynb_checkpoints/'.format(args.os_user))
+        conn.sudo('rm -rf /home/{}/.local/share/jupyter/'.format(args.os_user))
+        conn.sudo('rm -f /etc/systemd/system/jupyterlab-notebook.service')
+        conn.sudo('systemctl daemon-reload')
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        sys.exit(1)
 
 def clean_zeppelin():
     try:
@@ -114,6 +128,16 @@
         print('Error: {0}'.format(err))
         sys.exit(1)
 
+def clean_tensor_jupyterlab():
+    try:
+        clean_jupyterlab()
+        conn.sudo('systemctl stop tensorboard')
+        conn.sudo('systemctl disable tensorboard')
+        conn.sudo('systemctl daemon-reload')
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        sys.exit(1)
+
 def clean_deeplearning():
     try:
         conn.sudo('systemctl stop ungit')
@@ -178,6 +202,8 @@
                     clean_tensor()
                 elif args.application == 'tensor-rstudio':
                     clean_tensor_rstudio()
+                elif args.application == 'tensor-jupyterlab':
+                    clean_tensor_jupyterlab()
     else:
         print('Found default ami, do not make clean')
     #conn.close()
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/common_install_gpu.py b/infrastructure-provisioning/src/general/scripts/os/common_install_gpu.py
similarity index 100%
rename from infrastructure-provisioning/src/general/scripts/gcp/common_install_gpu.py
rename to infrastructure-provisioning/src/general/scripts/os/common_install_gpu.py
diff --git a/infrastructure-provisioning/src/general/scripts/os/get_list_available_pkgs.py b/infrastructure-provisioning/src/general/scripts/os/get_list_available_pkgs.py
index 8e33b20..a9591d2 100644
--- a/infrastructure-provisioning/src/general/scripts/os/get_list_available_pkgs.py
+++ b/infrastructure-provisioning/src/general/scripts/os/get_list_available_pkgs.py
@@ -26,6 +26,7 @@
 import sys
 import time
 import xmlrpc.client
+import os
 from datalab.fab import *
 from datalab.notebook_lib import *
 from fabric import *
@@ -42,16 +43,25 @@
     try:
         for _ in range(100):
             pip_pkgs = dict()
-            client = xmlrpc.client.ServerProxy('https://pypi.python.org/pypi')
-            raw_pkgs = client.browse(["Programming Language :: Python :: " + version + ""])
-            all_pkgs = [i[0] for i in raw_pkgs]
-            if len(all_pkgs) != 0:
-                for pkg in all_pkgs:
-                    pip_pkgs[pkg] = "N/A"
-                return pip_pkgs
-            else:
-                time.sleep(5)
-                continue
+            attempt = 0
+            while attempt < 3:
+                try:
+                    client = xmlrpc.client.ServerProxy('https://pypi.python.org/pypi')
+                    raw_pkgs = client.browse(["Programming Language :: Python :: " + version + ""])
+                    all_pkgs = [i[0] for i in raw_pkgs]
+                    if len(all_pkgs) != 0:
+                        for pkg in all_pkgs:
+                            pip_pkgs[pkg] = "N/A"
+                        return pip_pkgs
+                    else:
+                        time.sleep(5)
+                        continue
+                except:
+                    attempt += 1
+                    time.sleep(10)
+            if attempt == 3:
+                logging.info("Unable to get available pip packages")
+                raise Exception
     except Exception as err:
         print('Error: {0}'.format(err))
         sys.exit(1)
@@ -60,15 +70,24 @@
 def get_uncategorised_pip_pkgs(all_pkgs_pip2, all_pkgs_pip3):
     try:
         pip_pkgs = dict()
-        client = xmlrpc.client.ServerProxy('https://pypi.python.org/pypi')
-        raw_pkgs = client.list_packages()
-        all_pkgs_other = []
-        for pkg in raw_pkgs:
-            if pkg not in all_pkgs_pip2 and pkg not in all_pkgs_pip3:
-                all_pkgs_other.append(pkg)
-        for pkg in all_pkgs_other:
-            pip_pkgs[pkg] = "N/A"
-        return pip_pkgs
+        attempts = 0
+        while attempts < 3:
+            try:
+                client = xmlrpc.client.ServerProxy('https://pypi.python.org/pypi')
+                raw_pkgs = client.list_packages()
+                all_pkgs_other = []
+                for pkg in raw_pkgs:
+                    if pkg not in all_pkgs_pip2 and pkg not in all_pkgs_pip3:
+                        all_pkgs_other.append(pkg)
+                for pkg in all_pkgs_other:
+                    pip_pkgs[pkg] = "N/A"
+                return pip_pkgs
+            except:
+                attempts += 1
+                time.sleep(10)
+        if attempts == 3:
+            logging.info("Unable to get uncategorised pip packages")
+            raise Exception
     except Exception as err:
         print('Error: {0}'.format(err))
         sys.exit(1)
@@ -85,10 +104,10 @@
     #elif args.group == 'pip2':
         #all_pkgs['pip2'] = get_available_pip_pkgs("2.7")
     elif args.group == 'pip3':
-        all_pkgs['pip3'] = get_available_pip_pkgs("3.8")
+        all_pkgs['pip3'] = get_available_pip_pkgs(os.environ['notebook_python_venv_version'][:3])
     elif args.group == 'others':
         all_pkgs['pip2'] = get_available_pip_pkgs("2.7")
-        all_pkgs['pip3'] = get_available_pip_pkgs("3.8")
+        all_pkgs['pip3'] = get_available_pip_pkgs(os.environ['notebook_python_venv_version'][:3])
         all_pkgs['others'] = get_uncategorised_pip_pkgs(all_pkgs['pip2'], all_pkgs['pip3'])
     elif args.group == 'r_pkg':
         all_pkgs['r_pkg'] = get_available_r_pkgs()
diff --git a/infrastructure-provisioning/src/general/scripts/os/superset_start.py b/infrastructure-provisioning/src/general/scripts/os/superset_start.py
index 9f976ae..9245128 100644
--- a/infrastructure-provisioning/src/general/scripts/os/superset_start.py
+++ b/infrastructure-provisioning/src/general/scripts/os/superset_start.py
@@ -33,11 +33,11 @@
 parser.add_argument('--os_user', type=str, default='')
 args = parser.parse_args()
 
-superset_dir = '/home/' + args.os_user + '/incubator-superset/contrib/docker'
+superset_dir = '/home/' + args.os_user + '/superset'
 
 def start_superset(superset_dir):
     try:
-        conn.sudo('''bash -c 'cd {} && docker-compose run --rm superset ./docker-init.sh' '''.format(superset_dir))
+        conn.sudo('''bash -c 'cd {} && docker-compose run --rm superset docker/docker-init.sh' '''.format(superset_dir))
         conn.sudo('cp /opt/datalab/templates/superset-notebook.service /tmp/')
         conn.sudo('sed -i \'s/OS_USER/{}/g\' /tmp/superset-notebook.service'.format(args.os_user))
         conn.sudo('cp /tmp/superset-notebook.service /etc/systemd/system/')
diff --git a/infrastructure-provisioning/src/general/templates/aws/edge_s3_policy.json b/infrastructure-provisioning/src/general/templates/aws/edge_s3_policy.json
index 06cef15..e270610 100644
--- a/infrastructure-provisioning/src/general/templates/aws/edge_s3_policy.json
+++ b/infrastructure-provisioning/src/general/templates/aws/edge_s3_policy.json
@@ -23,8 +23,8 @@
     {
       "Effect": "Allow",
       "Action": [
-        "s3:GetObject",
-        "s3:HeadObject"
+        "s3:HeadObject",
+        "s3:GetObject"
       ],
       "Resource": "arn:aws:s3:::SSN_BUCK/*"
     },
@@ -32,9 +32,12 @@
       "Effect": "Allow",
       "Action": [
         "s3:HeadObject",
-        "s3:PutObject",
-        "s3:GetObject",
-        "s3:DeleteObject"
+        "s3:Get*",
+        "s3:Delete*",
+        "s3:Put*",
+        "s3:ListBucket",
+        "s3:ListBucketMultipartUploads",
+        "s3:AbortMultipartUpload"
       ],
       "Resource": [
         "arn:aws:s3:::BUCKET_NAME/*",
diff --git a/infrastructure-provisioning/src/general/templates/aws/interpreter_spark.json b/infrastructure-provisioning/src/general/templates/aws/interpreter_spark.json
index 56eb105..1e503dd 100644
--- a/infrastructure-provisioning/src/general/templates/aws/interpreter_spark.json
+++ b/infrastructure-provisioning/src/general/templates/aws/interpreter_spark.json
@@ -1,119 +1,5 @@
 {
   "interpreterSettings": {
-    "2C6RJRBD1": {
-      "id": "2C6RJRBD1",
-      "name": "local_interpreter_python2",
-      "group": "spark",
-      "properties": {
-        "zeppelin.spark.printREPLOutput": {
-            "propertyName": "zeppelin.spark.printREPLOutput",
-            "value": "true",
-            "description": "Print REPL output",
-            "type": "checkbox"
-          },
-        "zeppelin.dep.additionalRemoteRepository": {
-            "envName": "ZEPPELIN_DEP_ADDITIONALREMOTEREPOSITORY",
-            "propertyName": "zeppelin.dep.additionalRemoteRepository",
-            "value": "spark-packages,http://dl.bintray.com/spark-packages/maven,false;",
-            "description": "",
-            "type": "string"
-          },
-        "zeppelin.spark.sql.stacktrace": {
-            "envName": "ZEPPELIN_SPARK_SQL_STACKTRACE",
-            "propertyName": "zeppelin.spark.sql.stacktrace",
-            "value": "false",
-            "description": "",
-            "type": "checkbox"
-          },
-        "zeppelin.spark.importImplicit":{
-            "envName": "ZEPPELIN_SPARK_IMPORTIMPLICIT",
-            "propertyName": "zeppelin.spark.importImplicit",
-            "value": "true",
-            "description": "",
-            "type": "checkbox"
-          },
-        "zeppelin.spark.concurrentSQL": {
-            "envName": "ZEPPELIN_SPARK_CONCURRENTSQL",
-            "propertyName": "zeppelin.spark.concurrentSQL",
-            "value": "false",
-            "description": "",
-            "type": "checkbox"
-          },
-        "zeppelin.spark.useHiveContext": {
-            "envName": "ZEPPELIN_SPARK_USEHIVECONTEXT",
-            "propertyName": "zeppelin.spark.useHiveContext",
-            "value": "true",
-            "description": "Use HiveContext instead of SQLContext if it is true.",
-            "type": "checkbox"
-          },
-        "zeppelin.pyspark.python": {
-            "envName": "ZEPPELIN_PYSPARK_PYTHON",
-            "propertyName": "zeppelin.pyspark.python",
-            "value": "python",
-            "description": "",
-            "type": "string"
-          },
-        "zeppelin.dep.localrepo": {
-            "envName": "ZEPPELIN_DEP_LOCALREPO",
-            "propertyName": "zeppelin.dep.localrepo",
-            "value": "local-repo",
-            "description": "",
-            "type": "string"
-          },
-        "zeppelin.spark.maxResult": {
-            "envName": "ZEPPELIN_SPARK_MAXRESULT",
-            "propertyName": "zeppelin.spark.maxResult",
-            "value": "1000",
-            "description": "Max number of Spark SQL result to display.",
-            "type": "number"
-          },
-        "master":{
-            "envName": "Master",
-            "propertyName": "spark.master",
-            "value": "local[*]",
-            "description": "Spark master uri. ex) spark://masterhost:7077",
-            "type": "string"
-          },
-        "spark.app.name": {
-            "envName": "SPARK_APP_NAME",
-            "propertyName": "spark.app.name",
-            "value": "Zeppelin",
-            "description": "The name of spark application.",
-            "type": "string"
-          },
-        "spark.hadoop.fs.s3a.endpoint": {
-            "envName": "SPARK_HADOOP_FS_S3A_ENDPOINT",
-            "propertyName": "spark.hadoop.fs.s3a.endpoint",
-            "value": "ENDPOINTURL",
-            "description": "",
-            "type": "string"
-          },
-        "spark.driver.memory": {
-              "envName": "MEMORY_DRIVER",
-              "propertyName": "spark.driver.memory",
-              "value": "DRIVER_MEMORY",
-              "description": "",
-              "type": "string"
-          }
-      },
-      "interpreterGroup": [
-        {
-          "class": "org.apache.zeppelin.spark.SparkInterpreter",
-          "name": "spark"
-        },
-        {
-          "class": "org.apache.zeppelin.spark.PySparkInterpreter",
-          "name": "pyspark"
-        }
-      ],
-      "dependencies": [],
-      "option": {
-        "remote": true,
-        "perNoteSession": false,
-        "perNoteProcess": false,
-        "isExistingProcess": false
-      }
-    },
     "2C6RJRBD2": {
       "id": "2C6RJRBD2",
       "name": "local_interpreter_python3",
@@ -208,6 +94,13 @@
               "value": "DRIVER_MEMORY",
               "description": "",
               "type": "string"
+          },
+        "spark.pyspark.python": {
+              "envName": "PYSPARK_PYTHON",
+              "propertyName": "spark.pyspark.python",
+              "value": "PYTHON_VENV_PATH",
+              "description": "",
+              "type": "string"
           }
       },
       "interpreterGroup": [
diff --git a/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/create_data_engine/config.xml b/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/create_data_engine/config.xml
index 8c993b3..a0339e5 100644
--- a/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/create_data_engine/config.xml
+++ b/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/create_data_engine/config.xml
@@ -77,6 +77,7 @@
                       <string>zeppelin</string>
                       <string>tensor</string>
                       <string>tensor-rstudio</string>
+                      <string>tensor-jupyterlab</string>
                     </a>
                   </choices>
                 </hudson.model.ChoiceParameterDefinition>
diff --git a/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/create_notebook_server/config.xml b/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/create_notebook_server/config.xml
index abacbb1..bd128f7 100644
--- a/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/create_notebook_server/config.xml
+++ b/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/create_notebook_server/config.xml
@@ -41,6 +41,7 @@
               <string>zeppelin</string>
               <string>tensor</string>
               <string>tensor-rstudio</string>
+              <string>tensor-jupyterlab</string>
               <string>deeplearning</string>
               <string>jupyterlab</string>
             </a>
diff --git a/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/start_notebook_server/config.xml b/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/start_notebook_server/config.xml
index ba6a405..cb03b84 100644
--- a/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/start_notebook_server/config.xml
+++ b/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/start_notebook_server/config.xml
@@ -46,6 +46,7 @@
               <string>zeppelin</string>
               <string>tensor</string>
               <string>tensor-rstudio</string>
+              <string>tensor-jupyterlab</string>
               <string>jupyterlab</string>
             </a>
           </choices>
diff --git a/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/stop_notebook_server/config.xml b/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/stop_notebook_server/config.xml
index 906d0ca..e9e9bc4 100644
--- a/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/stop_notebook_server/config.xml
+++ b/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/stop_notebook_server/config.xml
@@ -46,6 +46,7 @@
               <string>zeppelin</string>
               <string>tensor</string>
               <string>tensor-rstudio</string>
+              <string>tensor-jupyterlab</string>
               <string>jupyterlab</string>
             </a>
           </choices>
diff --git a/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/terminate_notebook_server/config.xml b/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/terminate_notebook_server/config.xml
index d6b726a..e6d77ab 100644
--- a/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/terminate_notebook_server/config.xml
+++ b/infrastructure-provisioning/src/general/templates/aws/jenkins_jobs/terminate_notebook_server/config.xml
@@ -46,6 +46,7 @@
               <string>zeppelin</string>
               <string>tensor</string>
               <string>tensor-rstudio</string>
+              <string>tensor-jupyterlab</string>
               <string>jupyterlab</string>
             </a>
           </choices>
diff --git a/infrastructure-provisioning/src/general/templates/azure/dataengine-service_interpreter_livy.json b/infrastructure-provisioning/src/general/templates/azure/dataengine-service_interpreter_livy.json
new file mode 100644
index 0000000..a3aedda
--- /dev/null
+++ b/infrastructure-provisioning/src/general/templates/azure/dataengine-service_interpreter_livy.json
@@ -0,0 +1,121 @@
+{
+   "id":"livy",
+   "name":"CLUSTERNAME",
+   "group":"livy",
+   "properties":{
+      "zeppelin.livy.url":{
+         "name":"zeppelin.livy.url",
+         "value":"http://HEADNODEIP:PORT",
+         "type":"url",
+         "description":"The URL for Livy Server."
+      },
+      "zeppelin.livy.session.create_timeout":{
+         "name":"zeppelin.livy.session.create_timeout",
+         "value":"120",
+         "type":"number",
+         "description":"Livy Server create session timeout (seconds)."
+      },
+      "livy.spark.driver.memory":{
+         "name":"livy.spark.driver.memory",
+         "value":"1g",
+         "type":"string",
+         "description":"Driver memory. ex) 512m, 32g"
+      },
+      "zeppelin.livy.pull_status.interval.millis":{
+         "name":"zeppelin.livy.pull_status.interval.millis",
+         "value":"1000",
+         "type":"number",
+         "description":"The interval for checking paragraph execution status"
+      },
+      "zeppelin.livy.maxLogLines":{
+         "name":"zeppelin.livy.maxLogLines",
+         "value":"1000",
+         "type":"number",
+         "description":"Max number of lines of logs"
+      },
+      "livy.spark.jars.packages":{
+         "name":"livy.spark.jars.packages",
+         "value":"",
+         "type":"textarea",
+         "description":"Adding extra libraries to livy interpreter"
+      },
+      "zeppelin.livy.displayAppInfo":{
+         "name":"zeppelin.livy.displayAppInfo",
+         "value":true,
+         "type":"checkbox",
+         "description":"Whether display app info"
+      },
+      "zeppelin.livy.spark.sql.maxResult":{
+         "name":"zeppelin.livy.spark.sql.maxResult",
+         "value":"1000",
+         "type":"number",
+         "description":"Max number of Spark SQL result to display."
+      },
+      "zeppelin.livy.spark.sql.field.truncate":{
+         "name":"zeppelin.livy.spark.sql.field.truncate",
+         "value":true,
+         "type":"checkbox",
+         "description":"If true, truncate field values longer than 20 characters."
+      },
+      "zeppelin.R.knitr":{
+         "name":"zeppelin.R.knitr",
+         "value":"true",
+         "type":"string"
+      },
+      "zeppelin.R.image.width":{
+         "name":"zeppelin.R.image.width",
+         "value":"100%",
+         "type":"string"
+      },
+      "zeppelin.R.cmd":{
+         "name":"zeppelin.R.cmd",
+         "value":"R",
+         "type":"string"
+      },
+      "zeppelin.R.render.options":{
+         "name":"zeppelin.R.render.options",
+         "value":"out.format \u003d \u0027html\u0027, comment \u003d NA, echo \u003d FALSE, results \u003d \u0027asis\u0027, message \u003d F, warning \u003d F",
+         "type":"string"
+      }
+   },
+   "status":"READY",
+   "interpreterGroup":[
+      {
+         "name":"spark",
+         "class":"org.apache.zeppelin.livy.LivySparkInterpreter",
+         "defaultInterpreter":true,
+         "editor":{
+            "language":"scala",
+            "editOnDblClick":false,
+            "completionKey":"TAB",
+            "completionSupport":true
+         }
+      },
+      {
+         "name":"pyspark3",
+         "class":"org.apache.zeppelin.livy.LivyPySpark3Interpreter",
+         "defaultInterpreter":false,
+         "editor":{
+            "language":"python",
+            "editOnDblClick":false,
+            "completionKey":"TAB",
+            "completionSupport":true
+         }
+      }
+   ],
+   "dependencies":[
+
+   ],
+   "option":{
+      "remote":true,
+      "port":-1,
+      "perNote":"shared",
+      "perUser":"scoped",
+      "isExistingProcess":false,
+      "setPermission":false,
+      "owners":[
+
+      ],
+      "isUserImpersonate":false
+   }
+}
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/general/templates/azure/dataengine-service_sparkmagic_config.json b/infrastructure-provisioning/src/general/templates/azure/dataengine-service_sparkmagic_config.json
new file mode 100644
index 0000000..d9907b4
--- /dev/null
+++ b/infrastructure-provisioning/src/general/templates/azure/dataengine-service_sparkmagic_config.json
@@ -0,0 +1,17 @@
+{
+  "kernel_python_credentials" : {
+    "username": "",
+    "password": "",
+    "url": "http://HEADNODEIP:PORT/",
+    "auth": "None"
+  },
+  "kernel_scala_credentials" : {
+    "username": "",
+    "password": "",
+    "url": "http://HEADNODEIP:PORT/",
+    "auth": "None"
+  },
+  "custom_headers" : {
+    "X-Requested-By": "livy"
+  }
+}
diff --git a/infrastructure-provisioning/src/general/templates/azure/interpreter_spark.json b/infrastructure-provisioning/src/general/templates/azure/interpreter_spark.json
index f10d445..1cc8317 100644
--- a/infrastructure-provisioning/src/general/templates/azure/interpreter_spark.json
+++ b/infrastructure-provisioning/src/general/templates/azure/interpreter_spark.json
@@ -1,86 +1,124 @@
 {
   "interpreterSettings": {
-    "python": {
-      "id": "python",
-      "name": "python",
-      "group": "python",
+    "local_interpreter_python3": {
+      "id": "local_interpreter_python3",
+      "name": "local_interpreter_python3",
+      "group": "spark",
       "properties": {
-        "zeppelin.python": {
-          "name": "zeppelin.python",
-          "value": "PYTHON_VENV_PATH",
-          "type": "string",
-          "description": "Python binary executable path. It is set to python by default.(assume python is in your $PATH)"
-        },
-        "zeppelin.python.maxResult": {
-          "name": "zeppelin.python.maxResult",
-          "value": "1000",
-          "type": "number",
-          "description": "Max number of dataframe rows to display."
-        },
-        "zeppelin.python.useIPython": {
-          "name": "zeppelin.python.useIPython",
-          "value": true,
-          "type": "checkbox",
-          "description": "Whether use IPython when it is available in `%python`"
-        },
-        "zeppelin.ipython.launch.timeout": {
-          "name": "zeppelin.ipython.launch.timeout",
-          "value": "30000",
-          "type": "number",
-          "description": "Time out for ipython launch"
-        },
-        "zeppelin.ipython.grpc.message_size": {
-          "name": "zeppelin.ipython.grpc.message_size",
-          "value": "33554432",
-          "type": "number",
-          "description": "grpc message size, default is 32M"
-        }
+        "zeppelin.spark.printREPLOutput": {
+            "propertyName": "zeppelin.spark.printREPLOutput",
+            "value": "true",
+            "description": "Print REPL output",
+            "type": "checkbox"
+          },
+        "zeppelin.dep.additionalRemoteRepository": {
+            "envName": "ZEPPELIN_DEP_ADDITIONALREMOTEREPOSITORY",
+            "propertyName": "zeppelin.dep.additionalRemoteRepository",
+            "value": "spark-packages,http://dl.bintray.com/spark-packages/maven,false;",
+            "description": "",
+            "type": "string"
+          },
+        "zeppelin.spark.sql.stacktrace": {
+            "envName": "ZEPPELIN_SPARK_SQL_STACKTRACE",
+            "propertyName": "zeppelin.spark.sql.stacktrace",
+            "value": "false",
+            "description": "",
+            "type": "checkbox"
+          },
+        "zeppelin.spark.importImplicit":{
+            "envName": "ZEPPELIN_SPARK_IMPORTIMPLICIT",
+            "propertyName": "zeppelin.spark.importImplicit",
+            "value": "true",
+            "description": "",
+            "type": "checkbox"
+          },
+        "zeppelin.spark.concurrentSQL": {
+            "envName": "ZEPPELIN_SPARK_CONCURRENTSQL",
+            "propertyName": "zeppelin.spark.concurrentSQL",
+            "value": "false",
+            "description": "",
+            "type": "checkbox"
+          },
+        "zeppelin.spark.useHiveContext": {
+            "envName": "ZEPPELIN_SPARK_USEHIVECONTEXT",
+            "propertyName": "zeppelin.spark.useHiveContext",
+            "value": "true",
+            "description": "Use HiveContext instead of SQLContext if it is true.",
+            "type": "checkbox"
+          },
+        "zeppelin.pyspark.python": {
+            "envName": "ZEPPELIN_PYSPARK_PYTHON",
+            "propertyName": "zeppelin.pyspark.python",
+            "value": "python3.5",
+            "description": "",
+            "type": "string"
+          },
+        "zeppelin.dep.localrepo": {
+            "envName": "ZEPPELIN_DEP_LOCALREPO",
+            "propertyName": "zeppelin.dep.localrepo",
+            "value": "local-repo",
+            "description": "",
+            "type": "string"
+          },
+        "zeppelin.spark.maxResult": {
+            "envName": "ZEPPELIN_SPARK_MAXRESULT",
+            "propertyName": "zeppelin.spark.maxResult",
+            "value": "1000",
+            "description": "Max number of Spark SQL result to display.",
+            "type": "number"
+          },
+        "master":{
+            "envName": "Master",
+            "propertyName": "spark.master",
+            "value": "local[*]",
+            "description": "Spark master uri. ex) spark://masterhost:7077",
+            "type": "string"
+          },
+        "spark.app.name": {
+            "envName": "SPARK_APP_NAME",
+            "propertyName": "spark.app.name",
+            "value": "Zeppelin",
+            "description": "The name of spark application.",
+            "type": "string"
+          },
+        "spark.hadoop.fs.s3a.endpoint": {
+            "envName": "SPARK_HADOOP_FS_S3A_ENDPOINT",
+            "propertyName": "spark.hadoop.fs.s3a.endpoint",
+            "value": "ENDPOINTURL",
+            "description": "",
+            "type": "string"
+          },
+        "spark.driver.memory": {
+              "envName": "MEMORY_DRIVER",
+              "propertyName": "spark.driver.memory",
+              "value": "DRIVER_MEMORY",
+              "description": "",
+              "type": "string"
+          },
+        "spark.pyspark.python": {
+              "envName": "PYSPARK_PYTHON",
+              "propertyName": "spark.pyspark.python",
+              "value": "PYTHON_VENV_PATH",
+              "description": "",
+              "type": "string"
+          }
       },
-      "status": "READY",
       "interpreterGroup": [
         {
-          "name": "python",
-          "class": "org.apache.zeppelin.python.PythonInterpreter",
-          "defaultInterpreter": true,
-          "editor": {
-            "language": "python",
-            "editOnDblClick": false,
-            "completionSupport": true
-          }
+          "class": "org.apache.zeppelin.spark.SparkInterpreter",
+          "name": "spark"
         },
         {
-          "name": "ipython",
-          "class": "org.apache.zeppelin.python.IPythonInterpreter",
-          "defaultInterpreter": false,
-          "editor": {
-            "language": "python",
-            "editOnDblClick": false,
-            "completionKey": "TAB",
-            "completionSupport": true
-          }
-        },
-        {
-          "name": "sql",
-          "class": "org.apache.zeppelin.python.PythonInterpreterPandasSql",
-          "defaultInterpreter": false,
-          "editor": {
-            "language": "sql",
-            "editOnDblClick": false,
-            "completionKey": "TAB",
-            "completionSupport": false
-          }
+          "class": "org.apache.zeppelin.spark.PySparkInterpreter",
+          "name": "pyspark"
         }
       ],
       "dependencies": [],
       "option": {
         "remote": true,
-        "port": -1,
-        "perNote": "shared",
-        "perUser": "shared",
-        "isExistingProcess": false,
-        "setPermission": false,
-        "owners": [],
-        "isUserImpersonate": false
+        "perNoteSession": false,
+        "perNoteProcess": false,
+        "isExistingProcess": false
       }
     },
     "livy": {
diff --git a/infrastructure-provisioning/src/general/templates/gcp/dataengine-service_cluster.json b/infrastructure-provisioning/src/general/templates/gcp/dataengine-service_cluster.json
index 98f2300..e2891d3 100644
--- a/infrastructure-provisioning/src/general/templates/gcp/dataengine-service_cluster.json
+++ b/infrastructure-provisioning/src/general/templates/gcp/dataengine-service_cluster.json
@@ -10,6 +10,7 @@
             "internalIpOnly": "true",
             "serviceAccount": "SERVICE_ACCOUNT",
             "metadata": {
+                "enable-oslogin": "FALSE",
                 "ssh-keys": "SSH_USER:SSH_PUBKEY"
             },
             "tags": [
diff --git a/infrastructure-provisioning/src/general/templates/os/debian/jupyterlab-notebook.service b/infrastructure-provisioning/src/general/templates/os/debian/jupyterlab-notebook.service
new file mode 100644
index 0000000..cf3fe43
--- /dev/null
+++ b/infrastructure-provisioning/src/general/templates/os/debian/jupyterlab-notebook.service
@@ -0,0 +1,35 @@
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+[Unit]
+Description=Jupyterlab notebook
+
+[Service]
+Type=simple
+PIDFile=/var/run/jupyterlab-notebook.pid
+ExecStart=/bin/bash -c "/usr/local/bin/jupyter lab"
+ExecStop=/bin/bash -c "for i in $(ps aux | grep jupyter | grep -v grep | awk '{print $2}'); do kill -9 $i; done"
+User=datalab-user
+Group=datalab-user
+WorkingDirectory=/home/datalab-user
+
+[Install]
+WantedBy=multi-user.target
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/general/templates/os/debian/superset-notebook.service b/infrastructure-provisioning/src/general/templates/os/debian/superset-notebook.service
index ef3b4bf..064a8b7 100644
--- a/infrastructure-provisioning/src/general/templates/os/debian/superset-notebook.service
+++ b/infrastructure-provisioning/src/general/templates/os/debian/superset-notebook.service
@@ -28,7 +28,7 @@
 Group=OS_USER
 ExecStart=/usr/bin/sudo docker-compose up
 ExecStop=/usr/bin/sudo docker-compose stop
-WorkingDirectory=/home/OS_USER/incubator-superset/contrib/docker
+WorkingDirectory=/home/OS_USER/superset
 TimeoutStopSec=120
 Restart=on-failure
 RestartSec=10
diff --git a/infrastructure-provisioning/src/general/templates/os/debian/ungit.service.18_04 b/infrastructure-provisioning/src/general/templates/os/debian/ungit.service.18_04
new file mode 100644
index 0000000..088a4fe
--- /dev/null
+++ b/infrastructure-provisioning/src/general/templates/os/debian/ungit.service.18_04
@@ -0,0 +1,36 @@
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+[Unit]
+Description=ungit
+
+[Service]
+Type=simple
+ExecStart=/usr/local/bin/ungit --port=8085 --no-b --ungitBindIp=0.0.0.0 --rootPath=/NOTEBOOK_NAME-ungit
+User=OS_USR
+Group=OS_USR
+WorkingDirectory=/home/OS_USR/
+PIDFile=/var/run/ungit.pid
+Environment="HTTPS_PROXY=PROXY_HOST"
+Environment="HTTP_PROXY=PROXY_HOST"
+
+[Install]
+WantedBy=multi-user.target
diff --git a/infrastructure-provisioning/src/jupyter-gpu/fabfile.py b/infrastructure-provisioning/src/jupyter-gpu/fabfile.py
new file mode 100644
index 0000000..cee6a85
--- /dev/null
+++ b/infrastructure-provisioning/src/jupyter-gpu/fabfile.py
@@ -0,0 +1,255 @@
+#!/usr/bin/python3
+
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+# 
+#   http://www.apache.org/licenses/LICENSE-2.0
+# 
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+import logging
+import os
+import sys
+import uuid
+import subprocess
+from datalab.actions_lib import *
+from datalab.fab import *
+from datalab.meta_lib import *
+
+
+# Main function for provisioning notebook server
+@task
+def run(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] + "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    notebook_config = dict()
+    notebook_config['uuid'] = str(uuid.uuid4())[:5]
+
+    try:
+        params = "--uuid {}".format(notebook_config['uuid'])
+        subprocess.run("~/scripts/{}.py {}".format('common_prepare_notebook', params), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed preparing Notebook node.", str(err))
+        sys.exit(1)
+
+    try:
+        params = "--uuid {}".format(notebook_config['uuid'])
+        subprocess.run("~/scripts/{}.py {}".format('jupyter-gpu_configure', params), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed configuring Notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for terminating exploratory environment
+@task
+def terminate(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'], os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] + "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+    try:
+        subprocess.run("~/scripts/{}.py".format('common_terminate_notebook'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed terminating Notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for stopping notebook server
+@task
+def stop(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'], os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] +  "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+    try:
+        subprocess.run("~/scripts/{}.py".format('common_stop_notebook'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed stopping Notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for starting notebook server
+@task
+def start(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'], os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] +  "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        subprocess.run("~/scripts/{}.py".format('common_start_notebook'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed starting Notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for configuring notebook server after deploying DataEngine service
+@task
+def configure(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'], os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] +  "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        if os.environ['conf_resource'] == 'dataengine-service':
+            subprocess.run("~/scripts/{}.py".format('common_notebook_configure_dataengine-service'), shell=True, check=True)
+        elif os.environ['conf_resource'] == 'dataengine':
+            subprocess.run("~/scripts/{}.py".format('common_notebook_configure_dataengine'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed configuring analytical tool on Notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for installing additional libraries for notebook
+@task
+def install_libs(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] + "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        subprocess.run("~/scripts/{}.py".format('notebook_install_libs'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed installing additional libs for Notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for get available libraries for notebook
+@task
+def list_libs(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] + "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        subprocess.run("~/scripts/{}.py".format('notebook_list_libs'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed get available libraries for notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for manage git credentials on notebook
+@task
+def git_creds(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] + "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        subprocess.run("~/scripts/{}.py".format('notebook_git_creds'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed to manage git credentials for notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for creating image from notebook
+@task
+def create_image(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] + "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        subprocess.run("~/scripts/{}.py".format('common_create_notebook_image'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed to create image from notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for deleting existing notebook image
+@task
+def terminate_image(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] + "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        subprocess.run("~/scripts/{}.py".format('common_terminate_notebook_image'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed to create image from notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for reconfiguring Spark for notebook
+@task
+def reconfigure_spark(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] + "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        subprocess.run("~/scripts/{}.py".format('notebook_reconfigure_spark'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed to reconfigure Spark for Notebook node.", str(err))
+        sys.exit(1)
+
+# Main function for checking inactivity status
+@task
+def check_inactivity(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] + "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        subprocess.run("~/scripts/{}.py".format('notebook_inactivity_check'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed to check inactivity status.", str(err))
+        sys.exit(1)
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/jupyter-gpu/scripts/configure_jupyter-gpu_node.py b/infrastructure-provisioning/src/jupyter-gpu/scripts/configure_jupyter-gpu_node.py
new file mode 100644
index 0000000..a40fc81
--- /dev/null
+++ b/infrastructure-provisioning/src/jupyter-gpu/scripts/configure_jupyter-gpu_node.py
@@ -0,0 +1,159 @@
+#!/usr/bin/python3
+
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+import argparse
+import os
+import sys
+from datalab.actions_lib import *
+from datalab.fab import *
+from datalab.notebook_lib import *
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--hostname', type=str, default='')
+parser.add_argument('--keyfile', type=str, default='')
+parser.add_argument('--region', type=str, default='')
+parser.add_argument('--spark_version', type=str, default='')
+parser.add_argument('--hadoop_version', type=str, default='')
+parser.add_argument('--os_user', type=str, default='')
+parser.add_argument('--scala_version', type=str, default='')
+parser.add_argument('--ip_address', type=str, default='')
+parser.add_argument('--exploratory_name', type=str, default='')
+parser.add_argument('--edge_ip', type=str, default='')
+args = parser.parse_args()
+
+spark_version = args.spark_version
+hadoop_version = args.hadoop_version
+jupyter_version = os.environ['notebook_jupyter_version']
+python_venv_version = os.environ['notebook_python_venv_version']
+scala_link = "https://www.scala-lang.org/files/archive/"
+if args.region == 'cn-north-1':
+    spark_link = "http://mirrors.hust.edu.cn/apache/spark/spark-" + spark_version + "/spark-" + spark_version + \
+                 "-bin-hadoop" + hadoop_version + ".tgz"
+else:
+    spark_link = "https://archive.apache.org/dist/spark/spark-" + spark_version + "/spark-" + spark_version + \
+                 "-bin-hadoop" + hadoop_version + ".tgz"
+python_venv_path = '/opt/python/python{0}/bin/python{1}'.format(python_venv_version, python_venv_version[:3])
+pyspark_local_path_dir = '/home/' + args.os_user + '/.local/share/jupyter/kernels/pyspark_local/'
+py3spark_local_path_dir = '/home/' + args.os_user + '/.local/share/jupyter/kernels/py3spark_local/'
+jupyter_conf_file = '/home/' + args.os_user + '/.local/share/jupyter/jupyter_notebook_config.py'
+scala_kernel_path = '/usr/local/share/jupyter/kernels/apache_toree_scala/'
+r_kernels_dir = '/home/' + args.os_user + '/.local/share/jupyter/kernels/'
+jars_dir = '/opt/jars/'
+templates_dir = '/root/templates/'
+files_dir = '/root/files/'
+local_spark_path = '/opt/spark/'
+toree_link = 'https://dist.apache.org/repos/dist/dev/incubator/toree/0.5.0-incubating-rc1/toree-pip/toree-0.5.0.tar.gz'
+r_libs = ['R6', 'pbdZMQ={}'.format(os.environ['notebook_pbdzmq_version']), 'RCurl', 'reshape2', 'caTools={}'.format(os.environ['notebook_catools_version']), 'rJava', 'ggplot2']
+gitlab_certfile = os.environ['conf_gitlab_certfile']
+venv_libs = 'numpy scipy pandas scikit-learn python-git transformers==4.4.2 gensim==4.0.1 tokenizers==0.10.1 python-levenshtein==0.12.2'
+
+
+##############
+# Run script #
+##############
+if __name__ == "__main__":
+    print("Configure connections")
+    global conn
+    conn = datalab.fab.init_datalab_connection(args.hostname, args.os_user, args.keyfile)
+
+    # PREPARE DISK
+    print("Prepare .ensure directory")
+    try:
+        if not exists(conn,'/home/' + args.os_user + '/.ensure_dir'):
+            conn.sudo('mkdir /home/' + args.os_user + '/.ensure_dir')
+    except:
+        sys.exit(1)
+    print("Mount additional volume")
+    prepare_disk(args.os_user)
+
+    # INSTALL LANGUAGES
+    print("Install Java")
+    ensure_jre_jdk(args.os_user)
+    print("Install Scala")
+    ensure_scala(scala_link, args.scala_version, args.os_user)
+    print("Install Python 3 modules")
+    ensure_python3_libraries(args.os_user)
+
+    # INSTALL PYTHON IN VIRTUALENV
+    print("Configure Python Virtualenv")
+    ensure_python_venv(python_venv_version)
+
+    # INSTALL JUPYTER NOTEBOOK
+    print("Install Jupyter")
+    configure_jupyter(args.os_user, jupyter_conf_file, templates_dir, jupyter_version, args.exploratory_name)
+
+    # INSTALL SPARK AND CLOUD STORAGE JARS FOR SPARK
+    print("Install local Spark")
+    ensure_local_spark(args.os_user, spark_link, spark_version, hadoop_version, local_spark_path)
+    local_spark_scala_version = conn.run(
+        'export PATH=$PATH:' + local_spark_path + 'bin/; spark-submit --version 2>&1 | grep -o -P "Scala version \K.{0,7}"').stdout.replace(
+        '\n', '')
+    print("Install storage jars")
+    ensure_local_jars(args.os_user, jars_dir)
+    print("Configure local Spark")
+    configure_local_spark(jars_dir, templates_dir)
+
+    # INSTALL JUPYTER KERNELS
+    #print("Install pyspark local kernel for Jupyter")
+    #ensure_pyspark_local_kernel(args.os_user, pyspark_local_path_dir, templates_dir, spark_version)
+    print("Install py3spark local kernel for Jupyter")
+    ensure_py3spark_local_kernel(args.os_user, py3spark_local_path_dir, templates_dir, spark_version, python_venv_path, python_venv_version)
+    print("Install Toree-Scala kernel for Jupyter")
+    ensure_toree_local_kernel(args.os_user, toree_link, scala_kernel_path, files_dir, local_spark_scala_version, spark_version)
+
+    # INSTALL UNGIT
+    print("Install nodejs")
+    install_nodejs(args.os_user)
+    print("Install ungit")
+    install_ungit(args.os_user, args.exploratory_name, args.edge_ip)
+    if exists(conn, '/home/{0}/{1}'.format(args.os_user, gitlab_certfile)):
+        install_gitlab_cert(args.os_user, gitlab_certfile)
+
+    # INSTALL INACTIVITY CHECKER
+    print("Install inactivity checker")
+    install_inactivity_checker(args.os_user, args.ip_address)
+
+    # INSTALL OPTIONAL PACKAGES
+    print("Installing additional Python packages")
+    ensure_additional_python_libs(args.os_user)
+    print("Install Matplotlib")
+    ensure_matplot(args.os_user)
+    print("Install SBT")
+    ensure_sbt(args.os_user)
+    print("Install Breeze")
+    add_breeze_library_local(args.os_user)
+    if os.environ['conf_cloud_provider'] == 'gcp':
+        print('Installing Pytorch')
+        ensure_pytorch(args.os_user)
+
+    # INSTALL PIP PACKAGES
+    print("Install python venv required libs")
+    ensure_venv_libs(args.os_user, venv_libs)
+
+    #POST INSTALLATION PROCESS
+    print("Updating pyOpenSSL library")
+    update_pyopenssl_lib(args.os_user)
+    print("Removing unexisting kernels")
+    remove_unexisting_kernel(args.os_user)
+
+    conn.close()
diff --git a/infrastructure-provisioning/src/jupyterlab/Dockerfile_jupyterlab b/infrastructure-provisioning/src/jupyterlab/Dockerfile_jupyterlab
index 9b19771..fa166ff 100644
--- a/infrastructure-provisioning/src/jupyterlab/Dockerfile_jupyterlab
+++ b/infrastructure-provisioning/src/jupyterlab/Dockerfile_jupyterlab
@@ -36,17 +36,15 @@
 RUN  sed -i 's|CONF_PATH|/etc/jupyter/jupyter_notebook_config.py|' /jupyterlab_run.sh \
   && chmod +x /jupyterlab_run.sh
 
-RUN apt update && apt install -y vim netcat-openbsd
+RUN apt update && apt install -y vim netcat-openbsd git
 
-RUN jupyter serverextension enable --py jupyterlab_git && \
-    echo "ENABLED PLUGINS:" && \
-    jupyter serverextension list
+RUN pip install --upgrade jupyterlab-git
 
-RUN jupyter labextension disable odahu-flow-jupyterlab-plugin && \
-    jupyter serverextension disable --py odahuflow.jupyterlab && \
+RUN echo "ENABLED PLUGINS:" && \
     jupyter serverextension list && \
     jupyter labextension list
 
+
 USER $NB_USER
 
 ENTRYPOINT ["/jupyterlab_run.sh", "-d"]
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/project/templates/conf.d/proxy.conf b/infrastructure-provisioning/src/project/templates/conf.d/proxy.conf
index c9ce32b..2f7d5aa 100644
--- a/infrastructure-provisioning/src/project/templates/conf.d/proxy.conf
+++ b/infrastructure-provisioning/src/project/templates/conf.d/proxy.conf
@@ -33,12 +33,12 @@
     }
     # SSL section
     proxy_buffering off;
-    ssl on;
+    # ssl on;
     ssl_certificate /etc/ssl/certs/datalab.crt;
     ssl_certificate_key /etc/ssl/certs/datalab.key;
     ssl_session_timeout 5m;
-    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
+    ssl_protocols TLSv1.2 TLSv1.3;
+    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:!DSS';
     ssl_prefer_server_ciphers on;
     # ssl_dhparam /etc/ssl/certs/dhparam.pem;
 
diff --git a/infrastructure-provisioning/src/project/templates/locations/jupyter-gpu.conf b/infrastructure-provisioning/src/project/templates/locations/jupyter-gpu.conf
new file mode 100644
index 0000000..56f98ed
--- /dev/null
+++ b/infrastructure-provisioning/src/project/templates/locations/jupyter-gpu.conf
@@ -0,0 +1,29 @@
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+location ~* /{{ NAME }}/.* {
+    proxy_pass http://{{ IP }}:8888;
+    proxy_set_header Host $http_host;
+    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+    proxy_set_header X-Real-IP $remote_addr;
+    proxy_http_version 1.1;
+    proxy_set_header Upgrade $http_upgrade;
+    proxy_set_header Connection "upgrade";
+}
diff --git a/infrastructure-provisioning/src/project/templates/squid.conf b/infrastructure-provisioning/src/project/templates/squid.conf
index 39a6cbf..7ee5856 100644
--- a/infrastructure-provisioning/src/project/templates/squid.conf
+++ b/infrastructure-provisioning/src/project/templates/squid.conf
@@ -42,7 +42,7 @@
 http_access allow localhost manager
 http_access deny manager
 http_access allow DataLab_user_src_subnet
-http_access allow AllowedCIDRS
+#http_access allow AllowedCIDRS
 http_access allow localhost
 http_access deny all
 
diff --git a/infrastructure-provisioning/src/ssn/files/aws/mongo_roles.json b/infrastructure-provisioning/src/ssn/files/aws/mongo_roles.json
index fe0fc80..0cf3712 100644
--- a/infrastructure-provisioning/src/ssn/files/aws/mongo_roles.json
+++ b/infrastructure-provisioning/src/ssn/files/aws/mongo_roles.json
@@ -150,6 +150,16 @@
     ]
   },
   {
+    "_id": "nbCreateTensorJupyterlab",
+    "description": "Create Notebook JupyterLab with TensorFlow",
+    "exploratories": [
+      "docker.datalab-tensor-jupyterlab"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "nbCreateTensorRstudio",
     "description": "Create Notebook RStudio with TensorFlow",
     "exploratories": [
@@ -180,6 +190,16 @@
     ]
   },
   {
+    "_id": "compShapes_c4.large_fetching",
+    "description": "Use c4.large instance shape for cluster",
+    "computational_shapes": [
+      "c4.large"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "compShapes_c4.xlarge_fetching",
     "description": "Use c4.xlarge instance shape for cluster",
     "computational_shapes": [
diff --git a/infrastructure-provisioning/src/ssn/files/azure/mongo_roles.json b/infrastructure-provisioning/src/ssn/files/azure/mongo_roles.json
index 8da2754..649bda7 100644
--- a/infrastructure-provisioning/src/ssn/files/azure/mongo_roles.json
+++ b/infrastructure-provisioning/src/ssn/files/azure/mongo_roles.json
@@ -100,6 +100,16 @@
     ]
   },
   {
+    "_id": "nbCreateJupyterLab",
+    "description": "Create Notebook JupyterLab",
+    "exploratories": [
+      "docker.datalab-jupyterlab"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "nbCreateRstudio",
     "description": "Create Notebook RStudio",
     "exploratories": [
@@ -140,6 +150,26 @@
     ]
   },
   {
+    "_id": "nbCreateDataEngineService",
+    "description": "Create Data Engine Service",
+    "computationals": [
+      "docker.datalab-dataengine-service"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
+    "_id": "compShapes_Standard_D12_v2_fetching",
+    "description": "Use Standard_D12_v2 instance shape for cluster",
+    "computational_shapes": [
+      "Standard_D12_v2"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "compShapes_Standard_F4s_fetching",
     "description": "Use Standard_F4s instance shape for cluster",
     "computational_shapes": [
@@ -150,6 +180,16 @@
     ]
   },
   {
+    "_id": "compShapes_Standard_E4_v3_fetching",
+    "description": "Use Standard_E4_v3 instance shape for cluster",
+    "computational_shapes": [
+      "Standard_E4_v3"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "compShapes_Standard_E4s_v3_fetching",
     "description": "Use Standard_E4s_v3 instance shape for cluster",
     "computational_shapes": [
@@ -160,6 +200,16 @@
     ]
   },
   {
+    "_id": "compShapes_Standard_E16_v3_fetching",
+    "description": "Use Standard_E16_v3 instance shape for cluster",
+    "computational_shapes": [
+      "Standard_E16_v3"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "compShapes_Standard_E16s_v3_fetching",
     "description": "Use Standard_E16s_v3 instance shape for cluster",
     "computational_shapes": [
@@ -170,6 +220,16 @@
     ]
   },
   {
+    "_id": "compShapes_Standard_E32_v3_fetching",
+    "description": "Use Standard_E32_v3 instance shape for cluster",
+    "computational_shapes": [
+      "Standard_E32_v3"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "compShapes_Standard_E32s_v3_fetching",
     "description": "Use Standard_E32s_v3 instance shape for cluster",
     "computational_shapes": [
diff --git a/infrastructure-provisioning/src/ssn/files/gcp/mongo_roles.json b/infrastructure-provisioning/src/ssn/files/gcp/mongo_roles.json
index badb966..18fdb22 100644
--- a/infrastructure-provisioning/src/ssn/files/gcp/mongo_roles.json
+++ b/infrastructure-provisioning/src/ssn/files/gcp/mongo_roles.json
@@ -1,5 +1,15 @@
 [
   {
+    "_id": "nbShapes_a2-highgpu-1g_fetching",
+    "description": "Use a2-highgpu-1g instance shape for notebook",
+    "exploratory_shapes": [
+      "a2-highgpu-1g"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "nbShapes_n1-highcpu-2_fetching",
     "description": "Use n1-highcpu-2 instance shape for notebook",
     "exploratory_shapes": [
@@ -90,6 +100,16 @@
     ]
   },
   {
+    "_id": "nbCreateJupyterGpu",
+    "description": "Create Notebook Jupyter Gpu",
+    "exploratories": [
+      "docker.datalab-jupyter-gpu"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "nbCreateJupyterLab",
     "description": "Create Notebook JupyterLab",
     "exploratories": [
@@ -240,6 +260,16 @@
     ]
   },
   {
+    "_id": "compShapes_a2-highgpu-1g_fetching",
+    "description": "Use a2-highgpu-1g instance shape for cluster",
+    "computational_shapes": [
+      "a2-highgpu-1g"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "nbBillingReportFull",
     "description": "View full billing report for all users",
     "pages": [
diff --git a/infrastructure-provisioning/src/ssn/scripts/configure_billing.py b/infrastructure-provisioning/src/ssn/scripts/configure_billing.py
index f3357a5..186ae8a 100644
--- a/infrastructure-provisioning/src/ssn/scripts/configure_billing.py
+++ b/infrastructure-provisioning/src/ssn/scripts/configure_billing.py
@@ -76,6 +76,7 @@
 parser.add_argument('--keycloak_client_id', type=str, help='Keycloak client id')
 parser.add_argument('--keycloak_client_secret', type=str, help='Keycloak client secret')
 parser.add_argument('--keycloak_auth_server_url', type=str, help='Keycloak auth server url')
+parser.add_argument('--keycloak_realm_name', type=str, help='Keycloak Realm name')
 args = parser.parse_args()
 
 
@@ -107,6 +108,7 @@
             config_orig = config_orig.replace('COST', args.cost)
             config_orig = config_orig.replace('RESOURCE_ID', args.resource_id)
             config_orig = config_orig.replace('TAGS', args.tags)
+            config_orig = config_orig.replace('KEYCLOAK_REALM_NAME', args.keycloak_realm_name)
         elif args.cloud_provider == 'azure':
             config_orig = config_orig.replace('SERVICE_BASE_NAME', args.service_base_name)
             config_orig = config_orig.replace('OS_USER', args.os_user)
@@ -126,6 +128,7 @@
             config_orig = config_orig.replace('CURRENCY', args.currency)
             config_orig = config_orig.replace('LOCALE', args.locale)
             config_orig = config_orig.replace('REGION_INFO', args.region_info)
+            config_orig = config_orig.replace('KEYCLOAK_REALM_NAME', args.keycloak_realm_name)
         elif args.cloud_provider == 'gcp':
             config_orig = config_orig.replace('SERVICE_BASE_NAME', args.service_base_name)
             config_orig = config_orig.replace('OS_USER', args.os_user)
@@ -137,6 +140,7 @@
             config_orig = config_orig.replace('KEYCLOAK_CLIENT_ID', args.keycloak_client_id)
             config_orig = config_orig.replace('KEYCLOAK_CLIENT_SECRET', args.keycloak_client_secret)
             config_orig = config_orig.replace('KEYCLOAK_AUTH_SERVER_URL', args.keycloak_auth_server_url)
+            config_orig = config_orig.replace('KEYCLOAK_REALM_NAME', args.keycloak_realm_name)
         f = open(path, 'w')
         f.write(config_orig)
         f.close()
@@ -157,6 +161,7 @@
         config_orig = config_orig.replace('KEYCLOAK_CLIENT_ID', args.keycloak_client_id)
         config_orig = config_orig.replace('KEYCLOAK_CLIENT_SECRET', args.keycloak_client_secret)
         config_orig = config_orig.replace('KEYCLOAK_AUTH_SERVER_URL', args.keycloak_auth_server_url)
+        config_orig = config_orig.replace('KEYCLOAK_REALM_NAME', args.keycloak_realm_name)
 
         f = open(path, 'w')
         f.write(config_orig)
diff --git a/infrastructure-provisioning/src/ssn/scripts/configure_docker.py b/infrastructure-provisioning/src/ssn/scripts/configure_docker.py
index 1e6e31d..e11ee85 100644
--- a/infrastructure-provisioning/src/ssn/scripts/configure_docker.py
+++ b/infrastructure-provisioning/src/ssn/scripts/configure_docker.py
@@ -52,8 +52,8 @@
     for os_var in os.environ:
         if "'" not in os.environ[os_var] and os_var != 'aws_access_key' and os_var != 'aws_secret_access_key':
             variables_list[os_var] = os.environ[os_var]
-    conn.local('scp -r -i {} /project_tree/* {}:{}sources/'.format(args.keyfile, host_string, args.datalab_path))
-    conn.local('scp -i {} /root/scripts/configure_conf_file.py {}:/tmp/configure_conf_file.py'.format(args.keyfile,
+    conn.local('rsync -r -e "ssh -i {}" /project_tree/* {}:{}sources/'.format(args.keyfile, host_string, args.datalab_path))
+    conn.local('rsync -e "ssh -i {}" /root/scripts/configure_conf_file.py {}:/tmp/configure_conf_file.py'.format(args.keyfile,
                                                                                                  host_string))
     conn.sudo("python3 /tmp/configure_conf_file.py --datalab_dir {} --variables_list '{}'".format(
         args.datalab_path, json.dumps(variables_list)))
@@ -92,7 +92,7 @@
                 host_string = '{}@{}'.format(args.os_user, args.hostname)
                 with open('/tmp/config', 'w') as f:
                     f.write(base64.b64decode(gcr_creds))
-                conn.local('scp -i {} /tmp/config {}:/tmp/config'.format(args.keyfile, host_string, os_user))
+                conn.local('rsync -e "ssh -i {}" /tmp/config {}:/tmp/config'.format(args.keyfile, host_string, os_user))
                 conn.sudo('mkdir /home/{}/.docker'.format(os_user))
                 conn.sudo('cp /tmp/config /home/{}/.docker/config.json'.format(os_user))
                 conn.sudo('sed -i "s|ODAHU_IMAGE|{}|" {}sources/infrastructure-provisioning/src/general/files/{}/odahu_Dockerfile'
@@ -110,7 +110,7 @@
     try:
         host_string = '{}@{}'.format(args.os_user, args.hostname)
         if os.environ['conf_cloud_provider'] == 'azure':
-            conn.local('scp -i {} /root/azure_auth.json {}:{}sources/infrastructure-provisioning/src/base/'
+            conn.local('rsync -e "ssh -i {}" /root/azure_auth.json {}:{}sources/infrastructure-provisioning/src/base/'
                        'azure_auth.json'.format(args.keyfile, host_string, args.datalab_path))
             conn.sudo('cp {0}sources/infrastructure-provisioning/src/base/azure_auth.json '
                       '/home/{1}/keys/azure_auth.json'.format(args.datalab_path, args.os_user))
@@ -150,7 +150,8 @@
     try:
         mysql_pass = id_generator()
         conn.sudo('docker run --name guacd --restart unless-stopped -d -p 4822:4822 guacamole/guacd')
-        conn.sudo('docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --mysql > initdb.sql')
+        conn.sudo('docker run --rm guacamole/guacamole:{} /opt/guacamole/bin/initdb.sh --mysql > initdb.sql'
+                  .format(os.environ['ssn_guacamole_image_tag']))
         conn.sudo('mkdir /tmp/scripts')
         conn.sudo('cp initdb.sql /tmp/scripts')
         conn.sudo('mkdir /opt/mysql')
@@ -167,7 +168,7 @@
              .format(mysql_pass))
         conn.sudo("docker run --name guacamole --restart unless-stopped --link guacd:guacd --link guac-mysql:mysql" \
              " -e MYSQL_DATABASE='guacamole' -e MYSQL_USER='guacamole' -e MYSQL_PASSWORD='{}'" \
-             " -d -p 8080:8080 guacamole/guacamole".format(mysql_pass))
+             " -d -p 8080:8080 guacamole/guacamole:{}".format(mysql_pass, os.environ['ssn_guacamole_image_tag']))
         # create cronjob for run containers on reboot
         conn.sudo('mkdir /opt/datalab/cron')
         conn.sudo('touch /opt/datalab/cron/mysql.sh')
@@ -177,7 +178,8 @@
         conn.sudo('bash -c "echo \"docker rm guacamole\" >> /opt/datalab/cron/mysql.sh"')
         conn.sudo('''bash -c "echo \\"docker run --name guacamole --restart unless-stopped --link guacd:guacd --link ''' \
                   '''guac-mysql:mysql -e MYSQL_DATABASE='guacamole' -e MYSQL_USER='guacamole' -e MYSQL_PASSWORD='{}' '''\
-                  '''-d -p 8080:8080 guacamole/guacamole\\" >> /opt/datalab/cron/mysql.sh"'''.format(mysql_pass))
+                  '''-d -p 8080:8080 guacamole/guacamole:{}\\" >> /opt/datalab/cron/mysql.sh"'''
+                  .format(mysql_pass, os.environ['ssn_guacamole_image_tag']))
         conn.sudo("bash -c '(crontab -l 2>/dev/null; echo \"@reboot sh /opt/datalab/cron/mysql.sh\") | crontab -'")
         return True
     except Exception as err:
diff --git a/infrastructure-provisioning/src/ssn/scripts/configure_mongo.py b/infrastructure-provisioning/src/ssn/scripts/configure_mongo.py
index 9b02cb0..d38acc4 100644
--- a/infrastructure-provisioning/src/ssn/scripts/configure_mongo.py
+++ b/infrastructure-provisioning/src/ssn/scripts/configure_mongo.py
@@ -72,8 +72,8 @@
 
 if __name__ == "__main__":
     mongo_passwd = "PASSWORD"
-    mongo_ip = read_yml_conf(path,'net','bindIp')
-    mongo_port = read_yml_conf(path,'net','port')
+    mongo_ip = read_yml_conf(path, 'net', 'bindIp')
+    mongo_port = read_yml_conf(path, 'net', 'port')
     #mongo_parameters = json.loads(args.mongo_parameters)
     # Setting up admin's password and enabling security
     client = MongoClient(mongo_ip + ':' + str(mongo_port))
@@ -82,7 +82,7 @@
         command = ['service', 'mongod', 'start']
         subprocess.call(command, shell=False)
         time.sleep(5)
-        client.datalabdb.add_user('admin', mongo_passwd, roles=[{'role': 'userAdminAnyDatabase', 'db': 'admin'}])
+        client.datalabdb.command('createUser', 'admin', pwd=mongo_passwd, roles=[{'role': 'userAdminAnyDatabase', 'db': 'admin'}])
         client.datalabdb.command('grantRolesToUser', "admin", roles=["readWrite"])
         # set_mongo_parameters(client, mongo_parameters)
         with open(args.datalab_path + 'tmp/local_endpoint.json', 'r') as data:
diff --git a/infrastructure-provisioning/src/ssn/scripts/configure_ssn_node.py b/infrastructure-provisioning/src/ssn/scripts/configure_ssn_node.py
index 4b0cde6..f411fbb 100644
--- a/infrastructure-provisioning/src/ssn/scripts/configure_ssn_node.py
+++ b/infrastructure-provisioning/src/ssn/scripts/configure_ssn_node.py
@@ -63,7 +63,7 @@
         key_name=keyfile.split("/")
         conn.sudo('mkdir -p /home/' + os_user + '/keys')
         conn.sudo('chown -R ' + os_user + ':' + os_user + ' /home/' + os_user + '/keys')
-        conn.local('scp -r -q -i {0} {0} {1}:/home/{3}/keys/{2}'.format(keyfile, host_string, key_name[-1], os_user))
+        conn.local('rsync -r -q -e "ssh -i {0}" {0} {1}:/home/{3}/keys/{2}'.format(keyfile, host_string, key_name[-1], os_user))
         conn.sudo('chmod 600 /home/' + os_user + '/keys/*.pem')
     except Exception as err:
         traceback.print_exc()
@@ -210,7 +210,7 @@
         conn.sudo('mkdir -p /usr/lib/python3.8/datalab/')
         conn.run('mkdir -p /tmp/datalab_libs/')
         subprocess.run(
-            'scp -i {} /usr/lib/python3.8/datalab/*.py {}:/tmp/datalab_libs/'.format(args.keyfile, host_string),
+            'rsync -e "ssh -i {}" /usr/lib/python3.8/datalab/*.py {}:/tmp/datalab_libs/'.format(args.keyfile, host_string),
             shell=True, check=True)
         conn.run('chmod a+x /tmp/datalab_libs/*')
         conn.sudo('mv /tmp/datalab_libs/* /usr/lib/python3.8/datalab/')
diff --git a/infrastructure-provisioning/src/ssn/scripts/configure_ui.py b/infrastructure-provisioning/src/ssn/scripts/configure_ui.py
index 556a575..5778869 100644
--- a/infrastructure-provisioning/src/ssn/scripts/configure_ui.py
+++ b/infrastructure-provisioning/src/ssn/scripts/configure_ui.py
@@ -78,6 +78,7 @@
 parser.add_argument('--keycloak_client_id', type=str, default=None)
 parser.add_argument('--keycloak_client_secret', type=str, default=None)
 parser.add_argument('--keycloak_auth_server_url', type=str, default=None)
+parser.add_argument('--keycloak_realm_name', type=str, default=None)
 args = parser.parse_args()
 
 datalab_conf_dir = args.datalab_path + 'conf/'
@@ -95,7 +96,7 @@
     try:
         conn.sudo('mkdir -p /usr/lib/python3.8/datalab/')
         conn.run('mkdir -p /tmp/datalab_libs/')
-        subprocess.run('scp -i {} /usr/lib/python3.8/datalab/*.py {}:/tmp/datalab_libs/'.format(args.keyfile, host_string), shell=True, check=True)
+        subprocess.run('rsync -e "ssh -i {}" /usr/lib/python3.8/datalab/*.py {}:/tmp/datalab_libs/'.format(args.keyfile, host_string), shell=True, check=True)
         conn.run('chmod a+x /tmp/datalab_libs/*')
         conn.sudo('mv /tmp/datalab_libs/* /usr/lib/python3.8/datalab/')
         if exists(conn, '/usr/lib64'):
@@ -113,23 +114,23 @@
                 subprocess.run('sed -i "s/MONGO_USR/mongodb/g" /root/templates/mongod.service_template', shell=True, check=True)
             elif os.environ['conf_os_family'] == 'redhat':
                 subprocess.run('sed -i "s/MONGO_USR/mongod/g" /root/templates/mongod.service_template', shell=True, check=True)
-            subprocess.run('scp -i {} /root/templates/mongod.service_template {}:/tmp/mongod.service'.format(args.keyfile,
+            subprocess.run('rsync -e "ssh -i {}" /root/templates/mongod.service_template {}:/tmp/mongod.service'.format(args.keyfile,
                                                                                                     host_string), shell=True, check=True)
             conn.sudo('mv /tmp/mongod.service /lib/systemd/system/mongod.service')
             conn.sudo('systemctl daemon-reload')
             conn.sudo('systemctl enable mongod.service')
         subprocess.run('sed -i "s|PASSWORD|{}|g" /root/scripts/resource_status.py'.format(mongo_passwd), shell=True, check=True)
-        subprocess.run('scp -i {} /root/scripts/resource_status.py {}:/tmp/resource_status.py'.format(args.keyfile,
+        subprocess.run('rsync -e "ssh -i {}" /root/scripts/resource_status.py {}:/tmp/resource_status.py'.format(args.keyfile,
                                                                                              host_string), shell=True, check=True)
         conn.sudo('mv /tmp/resource_status.py ' + os.environ['ssn_datalab_path'] + 'tmp/')
         subprocess.run('sed -i "s|PASSWORD|{}|g" /root/scripts/configure_mongo.py'.format(mongo_passwd), shell=True, check=True)
-        subprocess.run('scp -i {} /root/scripts/configure_mongo.py {}:/tmp/configure_mongo.py'.format(args.keyfile,
+        subprocess.run('rsync -e "ssh -i {}" /root/scripts/configure_mongo.py {}:/tmp/configure_mongo.py'.format(args.keyfile,
                                                                                              host_string), shell=True, check=True)
         conn.sudo('mv /tmp/configure_mongo.py ' + args.datalab_path + 'tmp/')
-        subprocess.run('scp -i {} /root/files/{}/mongo_roles.json {}:/tmp/mongo_roles.json'.format(args.keyfile,
+        subprocess.run('rsync -e "ssh -i {}" /root/files/{}/mongo_roles.json {}:/tmp/mongo_roles.json'.format(args.keyfile,
                                                                                           args.cloud_provider,
                                                                                           host_string), shell=True, check=True)
-        subprocess.run('scp -i {} /root/files/local_endpoint.json {}:/tmp/local_endpoint.json'.format(args.keyfile,
+        subprocess.run('rsync -e "ssh -i {}" /root/files/local_endpoint.json {}:/tmp/local_endpoint.json'.format(args.keyfile,
                                                                                              host_string), shell=True, check=True)
         conn.sudo('mv /tmp/mongo_roles.json ' + args.datalab_path + 'tmp/')
         conn.sudo('sed -i "s|DEF_ENDPOINT_NAME|{0}|g" /tmp/local_endpoint.json'.format(default_endpoint_name))
@@ -137,9 +138,6 @@
             os.environ['conf_cloud_provider'].upper()))
         conn.sudo('mv /tmp/local_endpoint.json ' + args.datalab_path + 'tmp/')
         conn.sudo('pip3 install -U six==1.15.0 patchwork')
-        conn.sudo("ls -la " + args.datalab_path + "tmp/")
-        conn.sudo("ls -la /etc/")
-        conn.sudo("lsblk")
         conn.sudo("python3 " + args.datalab_path + "tmp/configure_mongo.py --datalab_path {} ".format(
             args.datalab_path))
     except Exception as err:
@@ -260,6 +258,6 @@
              args.hostname, args.datalake_store_name, args.subscription_id, args.validate_permission_scope,
              args.datalab_id, args.usage_date, args.product, args.usage_type,
              args.usage, args.cost, args.resource_id, args.tags, args.billing_dataset_name, args.keycloak_client_id,
-             args.keycloak_client_secret, args.keycloak_auth_server_url)
+             args.keycloak_client_secret, args.keycloak_auth_server_url, args.keycloak_realm_name)
 
     conn.close()
diff --git a/infrastructure-provisioning/src/ssn/scripts/docker_build.py b/infrastructure-provisioning/src/ssn/scripts/docker_build.py
index f0ddafe..9c368b6 100644
--- a/infrastructure-provisioning/src/ssn/scripts/docker_build.py
+++ b/infrastructure-provisioning/src/ssn/scripts/docker_build.py
@@ -38,13 +38,10 @@
         'jupyterlab',
         'rstudio',
         'zeppelin',
-            'tensor',
-            'tensor-rstudio',
-            'deeplearning',
-            'dataengine',
-            'dataengine-service',
-            'superset'
-            ]
+        'tensor',
+        'deeplearning',
+        'dataengine',
+        'dataengine-service']
 else:
     node = sys.argv[1:]
 
@@ -56,12 +53,14 @@
             os_family = 'redhat'
         if subprocess.run("uname -r | awk -F '-' '{print $3}'", capture_output=True, shell=True, check=True).stdout.decode('UTF-8').rstrip("\n\r") == 'aws':
             cloud_provider = 'aws'
+            node.extend(['tensor-rstudio', 'tensor-jupyterlab'])
         elif subprocess.run("uname -r | awk -F '-' '{print $3}'", capture_output=True, shell=True, check=True).stdout.decode('UTF-8').rstrip("\n\r") == 'azure':
             cloud_provider = 'azure'
             if not path.exists('{}base/azure_auth.json'.format(src_path)):
                 subprocess.run('cp /home/datalab-user/keys/azure_auth.json {}base/azure_auth.json'.format(src_path), shell=True, check=True)
         else:
             cloud_provider = 'gcp'
+            node.extend(['tensor-rstudio', 'jupyter-gpu', 'superset'])
         subprocess.run('cd {2}; docker build --build-arg OS={0} --build-arg SRC_PATH= --file general/files/{1}/base_Dockerfile -t docker.datalab-base:latest .'.format(
                     os_family, cloud_provider, src_path), shell=True, check=True)
         try:
diff --git a/infrastructure-provisioning/src/ssn/scripts/gitlab_deploy.py b/infrastructure-provisioning/src/ssn/scripts/gitlab_deploy.py
index 813ea47..0653b94 100644
--- a/infrastructure-provisioning/src/ssn/scripts/gitlab_deploy.py
+++ b/infrastructure-provisioning/src/ssn/scripts/gitlab_deploy.py
@@ -25,7 +25,7 @@
 from fabric import *
 import argparse
 import boto3
-from botocore.client import Config as botoConfig`
+from botocore.client import Config as botoConfig
 import sys
 import os
 
diff --git a/infrastructure-provisioning/src/ssn/templates/nginx_proxy.conf b/infrastructure-provisioning/src/ssn/templates/nginx_proxy.conf
index 1fda167..bf7c970 100644
--- a/infrastructure-provisioning/src/ssn/templates/nginx_proxy.conf
+++ b/infrastructure-provisioning/src/ssn/templates/nginx_proxy.conf
@@ -36,12 +36,12 @@
     }
     # SSL section
     proxy_buffering off;
-    ssl on;
+    # ssl on;
     ssl_certificate /etc/ssl/certs/datalab.crt;
     ssl_certificate_key /etc/ssl/certs/datalab.key;
     ssl_session_timeout 5m;
-    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
-    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
+    ssl_protocols TLSv1.2 TLSv1.3;
+    ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:!DSS';
     ssl_prefer_server_ciphers on;
     # ssl_dhparam /etc/ssl/certs/dhparam.pem;
 
diff --git a/infrastructure-provisioning/src/superset/templates/docker-compose.yml b/infrastructure-provisioning/src/superset/templates/docker-compose.yml
index 78283cb..0ac164d 100644
--- a/infrastructure-provisioning/src/superset/templates/docker-compose.yml
+++ b/infrastructure-provisioning/src/superset/templates/docker-compose.yml
@@ -14,18 +14,34 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-version: '2'
+x-superset-image: &superset-image apache/superset:${TAG:-1.5.1}
+x-superset-user: &superset-user root
+x-superset-depends-on: &superset-depends-on
+  - db
+  - redis
+x-superset-volumes: &superset-volumes
+  # /app/pythonpath_docker will be appended to the PYTHONPATH in the final container
+  - ./docker:/app/docker
+  - ./superset:/app/superset
+  - ./superset-frontend:/app/superset-frontend
+  - superset_home:/app/superset_home
+  - ./tests:/app/tests
+
+version: "3.7"
 services:
   redis:
-    image: redis:3.2
+    image: redis:latest
+    container_name: superset_cache
     restart: unless-stopped
     ports:
       - "127.0.0.1:6379:6379"
     volumes:
       - redis:/data
 
-  postgres:
-    image: postgres:10
+  db:
+    env_file: docker/.env
+    image: postgres:14
+    container_name: superset_db
     restart: unless-stopped
     environment:
       POSTGRES_DB: superset
@@ -34,44 +50,112 @@
     ports:
       - "127.0.0.1:5432:5432"
     volumes:
-      - postgres:/var/lib/postgresql/data
+      - db_home:/var/lib/postgresql/data
 
   superset:
-    build:
-      context: ../../
-      dockerfile: contrib/docker/Dockerfile
+    env_file: docker/.env
+    image: *superset-image
+    container_name: superset_app
+    command: ["/app/docker/docker-bootstrap.sh", "app"]
     restart: unless-stopped
-    environment:
-      POSTGRES_DB: superset
-      POSTGRES_USER: superset
-      POSTGRES_PASSWORD: superset
-      POSTGRES_HOST: postgres
-      POSTGRES_PORT: 5432
-      REDIS_HOST: redis
-      REDIS_PORT: 6379
-      USERNAME_OIDC_FIELD: preferred_username
-      FIRST_NAME_OIDC_FIELD: given_name
-      LAST_NAME_OIDC_FIELD: family_name
-      http_proxy: http://PROXY_STRING
-      https_proxy: http://PROXY_STRING
-      # If using production, comment development volume below
-      SUPERSET_ENV: production
-      #SUPERSET_ENV: development
-    user: root:root
     ports:
       - 8088:8088
+    user: *superset-user
+    depends_on: *superset-depends-on
+    volumes: *superset-volumes
+    environment:
+      CYPRESS_CONFIG: "${CYPRESS_CONFIG}"
+
+  superset-websocket:
+    container_name: superset_websocket
+    build: ./superset-websocket
+    image: superset-websocket
+    ports:
+      - 8080:8080
     depends_on:
-      - postgres
       - redis
+    # Mount everything in superset-websocket into container and
+    # then exclude node_modules and dist with bogus volume mount.
+    # This is necessary because host and container need to have
+    # their own, separate versions of these files. .dockerignore
+    # does not seem to work when starting the service through
+    # docker-compose.
+    #
+    # For example, node_modules may contain libs with native bindings.
+    # Those bindings need to be compiled for each OS and the container
+    # OS is not necessarily the same as host OS.
     volumes:
-      # this is needed to communicate with the postgres and redis services
-      - ./superset_config.py:/home/superset/superset/superset_config.py
-      # this is needed for development, remove with SUPERSET_ENV=production
-      #- ../../superset:/home/superset/superset
-      - ./id_provider.json:/home/superset/superset/id_provider.json
+      - ./superset-websocket:/home/superset-websocket
+      - /home/superset-websocket/node_modules
+      - /home/superset-websocket/dist
+    environment:
+      - PORT=8080
+      - REDIS_HOST=redis
+      - REDIS_PORT=6379
+      - REDIS_SSL=false
+
+  superset-init:
+    image: *superset-image
+    container_name: superset_init
+    command: ["/app/docker/docker-init.sh"]
+    env_file: docker/.env
+    depends_on: *superset-depends-on
+    user: *superset-user
+    volumes: *superset-volumes
+    environment:
+      CYPRESS_CONFIG: "${CYPRESS_CONFIG}"
+
+  superset-node:
+    image: node:16
+    container_name: superset_node
+    command: ["/app/docker/docker-frontend.sh"]
+    env_file: docker/.env
+    depends_on: *superset-depends-on
+    volumes: *superset-volumes
+
+  superset-worker:
+    image: *superset-image
+    container_name: superset_worker
+    command: ["/app/docker/docker-bootstrap.sh", "worker"]
+    env_file: docker/.env
+    restart: unless-stopped
+    depends_on: *superset-depends-on
+    user: *superset-user
+    volumes: *superset-volumes
+    # Bump memory limit if processing selenium / thumbnails on superset-worker
+    # mem_limit: 2038m
+    # mem_reservation: 128M
+
+  superset-worker-beat:
+    image: *superset-image
+    container_name: superset_worker_beat
+    command: ["/app/docker/docker-bootstrap.sh", "beat"]
+    env_file: docker/.env
+    restart: unless-stopped
+    depends_on: *superset-depends-on
+    user: *superset-user
+    volumes: *superset-volumes
+
+  superset-tests-worker:
+    image: *superset-image
+    container_name: superset_tests_worker
+    command: ["/app/docker/docker-bootstrap.sh", "worker"]
+    env_file: docker/.env
+    environment:
+      DATABASE_HOST: localhost
+      DATABASE_DB: test
+      REDIS_CELERY_DB: 2
+      REDIS_RESULTS_DB: 3
+      REDIS_HOST: localhost
+    network_mode: host
+    depends_on: *superset-depends-on
+    user: *superset-user
+    volumes: *superset-volumes
 
 volumes:
-  postgres:
+  superset_home:
+    external: false
+  db_home:
     external: false
   redis:
     external: false
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/superset/templates/docker-init.sh b/infrastructure-provisioning/src/superset/templates/docker-init.sh
index 11b682a..d5c5d88 100644
--- a/infrastructure-provisioning/src/superset/templates/docker-init.sh
+++ b/infrastructure-provisioning/src/superset/templates/docker-init.sh
@@ -15,19 +15,59 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-set -ex
+set -e
 
-# Create an admin user (you will be prompted to set username, first and last name before setting a password)
-export FLASK_APP=superset:app
-#flask fab create-admin --username admin --firstname admin --lastname admin --password admin
+#
+# Always install local overrides first
+#
+/app/docker/docker-bootstrap.sh
 
+STEP_CNT=4
+
+echo_step() {
+cat <<EOF
+######################################################################
+Init Step ${1}/${STEP_CNT} [${2}] -- ${3}
+######################################################################
+EOF
+}
+ADMIN_PASSWORD="admin"
+# If Cypress run – overwrite the password for admin and export env variables
+if [ "$CYPRESS_CONFIG" == "true" ]; then
+    ADMIN_PASSWORD="general"
+    export SUPERSET_CONFIG=tests.integration_tests.superset_test_config
+    export SUPERSET_TESTENV=true
+    export ENABLE_REACT_CRUD_VIEWS=true
+    export SUPERSET__SQLALCHEMY_DATABASE_URI=postgresql+psycopg2://superset:superset@db:5432/superset
+fi
 # Initialize the database
+echo_step "1" "Starting" "Applying DB migrations"
 superset db upgrade
+echo_step "1" "Complete" "Applying DB migrations"
+
+# Create an admin user
+echo_step "2" "Starting" "Setting up admin user ( admin / $ADMIN_PASSWORD )"
+superset fab create-admin \
+              --username admin \
+              --firstname Superset \
+              --lastname Admin \
+              --email admin@superset.com \
+              --password $ADMIN_PASSWORD
+echo_step "2" "Complete" "Setting up admin user"
+# Create default roles and permissions
+echo_step "3" "Starting" "Setting up roles and perms"
+superset init
+echo_step "3" "Complete" "Setting up roles and perms"
 
 if [ "$SUPERSET_LOAD_EXAMPLES" = "yes" ]; then
     # Load some data to play with
-    superset load_examples
-fi
-
-# Create default roles and permissions
-superset init
+    echo_step "4" "Starting" "Loading examples"
+    # If Cypress run which consumes superset_test_config – load required data for tests
+    if [ "$CYPRESS_CONFIG" == "true" ]; then
+        superset load_test_users
+        superset load_examples --load-test-data
+    else
+        superset load_examples
+    fi
+    echo_step "4" "Complete" "Loading examples"
+fi
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/superset/templates/keycloak_security_manager.py b/infrastructure-provisioning/src/superset/templates/keycloak_security_manager.py
new file mode 100644
index 0000000..c7aee93
--- /dev/null
+++ b/infrastructure-provisioning/src/superset/templates/keycloak_security_manager.py
@@ -0,0 +1,71 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# This file is included in the final Docker image and SHOULD be overridden when
+# deploying the image to prod. Settings configured here are intended for use in local
+# development environments. Also note that superset_config_docker.py is imported
+# as a final step as a means to override "defaults" configured here
+#
+
+from flask_appbuilder.security.manager import AUTH_OID
+from superset.security import SupersetSecurityManager
+from flask_oidc import OpenIDConnect
+from flask_appbuilder.security.views import AuthOIDView
+from flask_login import login_user
+from urllib.parse import quote
+from flask_appbuilder.views import ModelView, SimpleFormView, expose
+import logging
+
+class OIDCSecurityManager(SupersetSecurityManager):
+
+    def __init__(self, appbuilder):
+        super(OIDCSecurityManager, self).__init__(appbuilder)
+        if self.auth_type == AUTH_OID:
+            self.oid = OpenIDConnect(self.appbuilder.get_app)
+        self.authoidview = AuthOIDCView
+
+class AuthOIDCView(AuthOIDView):
+
+    @expose('/login/', methods=['GET', 'POST'])
+    def login(self, flag=True):
+        sm = self.appbuilder.sm
+        oidc = sm.oid
+
+        @self.appbuilder.sm.oid.require_login
+        def handle_login():
+            user = sm.auth_user_oid(oidc.user_getfield('email'))
+
+            if user is None:
+                info = oidc.user_getinfo(['preferred_username', 'given_name', 'family_name', 'email'])
+                user = sm.add_user(info.get('preferred_username'), info.get('given_name'), info.get('family_name'),
+                                   info.get('email'), sm.find_role('Gamma'))
+
+            login_user(user, remember=False)
+            return redirect(self.appbuilder.get_url_for_index)
+
+        return handle_login()
+
+    @expose('/logout/', methods=['GET', 'POST'])
+    def logout(self):
+        oidc = self.appbuilder.sm.oid
+
+        oidc.logout()
+        super(AuthOIDCView, self).logout()
+        redirect_url = request.url_root.strip('/') + self.appbuilder.get_url_for_login
+
+        return redirect(
+            oidc.client_secrets.get('issuer') + '/protocol/openid-connect/logout?redirect_uri=' + quote(redirect_url))
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/superset/templates/requirements-extra.txt b/infrastructure-provisioning/src/superset/templates/requirements-extra.txt
index 6b6dcd7..f12843c 100644
--- a/infrastructure-provisioning/src/superset/templates/requirements-extra.txt
+++ b/infrastructure-provisioning/src/superset/templates/requirements-extra.txt
@@ -17,3 +17,5 @@
 gevent==1.4.0
 fab-oidc
 pybigquery
+flask-oidc==1.3.0
+flask-sqlalchemy
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/superset/templates/superset_config.py b/infrastructure-provisioning/src/superset/templates/superset_config.py
index b8830af..358e4b4 100644
--- a/infrastructure-provisioning/src/superset/templates/superset_config.py
+++ b/infrastructure-provisioning/src/superset/templates/superset_config.py
@@ -14,11 +14,26 @@
 # KIND, either express or implied.  See the License for the
 # specific language governing permissions and limitations
 # under the License.
+#
+# This file is included in the final Docker image and SHOULD be overridden when
+# deploying the image to prod. Settings configured here are intended for use in local
+# development environments. Also note that superset_config_docker.py is imported
+# as a final step as a means to override "defaults" configured here
+#
+import logging
 import os
-from fab_oidc.security import SupersetOIDCSecurityManager
-from flask_appbuilder.security.manager import AUTH_OID
+from datetime import timedelta
+from typing import Optional
+from keycloak_security_manager import OIDCSecurityManager
+from flask_appbuilder.security.manager import AUTH_OID, AUTH_REMOTE_USER, AUTH_DB, AUTH_LDAP, AUTH_OAUTH
+import os
+from cachelib.file import FileSystemCache
+from celery.schedules import crontab
 
-def get_env_variable(var_name, default=None):
+logger = logging.getLogger()
+
+
+def get_env_variable(var_name: str, default: Optional[str] = None) -> str:
     """Get the environment variable or raise exception."""
     try:
         return os.environ[var_name]
@@ -26,43 +41,85 @@
         if default is not None:
             return default
         else:
-            error_msg = 'The environment variable {} was missing, abort...'\
-                        .format(var_name)
+            error_msg = "The environment variable {} was missing, abort...".format(
+                var_name
+            )
             raise EnvironmentError(error_msg)
 
 
-POSTGRES_USER = get_env_variable('POSTGRES_USER')
-POSTGRES_PASSWORD = get_env_variable('POSTGRES_PASSWORD')
-POSTGRES_HOST = get_env_variable('POSTGRES_HOST')
-POSTGRES_PORT = get_env_variable('POSTGRES_PORT')
-POSTGRES_DB = get_env_variable('POSTGRES_DB')
+DATABASE_DIALECT = get_env_variable("DATABASE_DIALECT")
+DATABASE_USER = get_env_variable("DATABASE_USER")
+DATABASE_PASSWORD = get_env_variable("DATABASE_PASSWORD")
+DATABASE_HOST = get_env_variable("DATABASE_HOST")
+DATABASE_PORT = get_env_variable("DATABASE_PORT")
+DATABASE_DB = get_env_variable("DATABASE_DB")
 
 # The SQLAlchemy connection string.
-SQLALCHEMY_DATABASE_URI = 'postgresql://%s:%s@%s:%s/%s' % (POSTGRES_USER,
-                                                           POSTGRES_PASSWORD,
-                                                           POSTGRES_HOST,
-                                                           POSTGRES_PORT,
-                                                           POSTGRES_DB)
+SQLALCHEMY_DATABASE_URI = "%s://%s:%s@%s:%s/%s" % (
+    DATABASE_DIALECT,
+    DATABASE_USER,
+    DATABASE_PASSWORD,
+    DATABASE_HOST,
+    DATABASE_PORT,
+    DATABASE_DB,
+)
 
-REDIS_HOST = get_env_variable('REDIS_HOST')
-REDIS_PORT = get_env_variable('REDIS_PORT')
+REDIS_HOST = get_env_variable("REDIS_HOST")
+REDIS_PORT = get_env_variable("REDIS_PORT")
+REDIS_CELERY_DB = get_env_variable("REDIS_CELERY_DB", "0")
+REDIS_RESULTS_DB = get_env_variable("REDIS_RESULTS_DB", "1")
+
+RESULTS_BACKEND = FileSystemCache("/app/superset_home/sqllab")
 
 
 class CeleryConfig(object):
-    BROKER_URL = 'redis://%s:%s/0' % (REDIS_HOST, REDIS_PORT)
-    CELERY_IMPORTS = ('superset.sql_lab', )
-    CELERY_RESULT_BACKEND = 'redis://%s:%s/1' % (REDIS_HOST, REDIS_PORT)
-    CELERY_ANNOTATIONS = {'tasks.add': {'rate_limit': '10/s'}}
-    CELERY_TASK_PROTOCOL = 1
+    BROKER_URL = f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_CELERY_DB}"
+    CELERY_IMPORTS = ("superset.sql_lab", "superset.tasks")
+    CELERY_RESULT_BACKEND = f"redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_RESULTS_DB}"
+    CELERYD_LOG_LEVEL = "DEBUG"
+    CELERYD_PREFETCH_MULTIPLIER = 1
+    CELERY_ACKS_LATE = False
+    CELERYBEAT_SCHEDULE = {
+        "reports.scheduler": {
+            "task": "reports.scheduler",
+            "schedule": crontab(minute="*", hour="*"),
+        },
+        "reports.prune_log": {
+            "task": "reports.prune_log",
+            "schedule": crontab(minute=10, hour=0),
+        },
+    }
 
 
 CELERY_CONFIG = CeleryConfig
 
+FEATURE_FLAGS = {"ALERT_REPORTS": True}
+ALERT_REPORTS_NOTIFICATION_DRY_RUN = True
+WEBDRIVER_BASEURL = "http://superset:8088/"
+# The base URL for the email report hyperlinks.
+WEBDRIVER_BASEURL_USER_FRIENDLY = WEBDRIVER_BASEURL
+
+SQLLAB_CTAS_NO_LIMIT = True
+
+#
+# Optionally import superset_config_docker.py (which will have been included on
+# the PYTHONPATH) in order to allow for local settings to be overridden
+#
+try:
+    import superset_config_docker
+    from superset_config_docker import *  # noqa
+
+    logger.info(
+        f"Loaded your Docker configuration at " f"[{superset_config_docker.__file__}]"
+    )
+except ImportError:
+    logger.info("Using default Docker config...")
+
 AUTH_TYPE = AUTH_OID
 AUTH_USER_REGISTRATION = True
 AUTH_USER_REGISTRATION_ROLE = "Admin"
 CUSTOM_SECURITY_MANAGER = SupersetOIDCSecurityManager
-OIDC_CLIENT_SECRETS = '/home/superset/superset/id_provider.json'
+OIDC_CLIENT_SECRETS = '/home/OS_USER/superset/docker/id_provider.json'
 OIDC_COOKIE_SECURE = False
 OIDC_VALID_ISSUERS = 'KEYCLOAK_AUTH_SERVER_URL/realms/KEYCLOAK_REALM_NAME'
 WTF_CSRF_ENABLED = False
diff --git a/infrastructure-provisioning/src/tensor-jupyterlab/fabfile.py b/infrastructure-provisioning/src/tensor-jupyterlab/fabfile.py
new file mode 100644
index 0000000..133eb08
--- /dev/null
+++ b/infrastructure-provisioning/src/tensor-jupyterlab/fabfile.py
@@ -0,0 +1,254 @@
+#!/usr/bin/python3
+
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+import logging
+import os
+import sys
+import uuid
+import subprocess
+from datalab.actions_lib import *
+from datalab.fab import *
+from datalab.meta_lib import *
+
+
+# Main function for provisioning notebook server
+@task
+def run(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] + "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    notebook_config = dict()
+    notebook_config['uuid'] = str(uuid.uuid4())[:5]
+
+    try:
+        params = "--uuid {}".format(notebook_config['uuid'])
+        subprocess.run("~/scripts/{}.py {}".format('common_prepare_notebook', params), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed preparing Notebook node.", str(err))
+        sys.exit(1)
+
+    try:
+        params = "--uuid {}".format(notebook_config['uuid'])
+        subprocess.run("~/scripts/{}.py {}".format('tensor-jupyterlab_configure', params), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed configuring Notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for terminating exploratory environment
+@task
+def terminate(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'], os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] + "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+    try:
+        subprocess.run("~/scripts/{}.py".format('common_terminate_notebook'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed terminating Notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for stopping notebook server
+@task
+def stop(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'], os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] +  "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+    try:
+        subprocess.run("~/scripts/{}.py".format('common_stop_notebook'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed stopping Notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for starting notebook server
+@task
+def start(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'], os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] +  "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        subprocess.run("~/scripts/{}.py".format('common_start_notebook'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed starting Notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for configuring notebook server after deploying DataEngine service
+@task
+def configure(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] + "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        if os.environ['conf_resource'] == 'dataengine':
+            subprocess.run("~/scripts/{}.py".format('common_notebook_configure_dataengine'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed configuring dataengine on Notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for installing additional libraries for notebook
+@task
+def install_libs(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] + "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        subprocess.run("~/scripts/{}.py".format('notebook_install_libs'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed installing additional libs for Notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for get available libraries for notebook
+@task
+def list_libs(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] + "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        subprocess.run("~/scripts/{}.py".format('notebook_list_libs'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed get available libraries for notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for manage git credentials on notebook
+@task
+def git_creds(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] + "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        subprocess.run("~/scripts/{}.py".format('notebook_git_creds'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed to manage git credentials for notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for creating image from notebook
+@task
+def create_image(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] + "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        subprocess.run("~/scripts/{}.py".format('common_create_notebook_image'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed to create image from notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for deleting existing notebook image
+@task
+def terminate_image(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] + "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        subprocess.run("~/scripts/{}.py".format('common_terminate_notebook_image'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed to create image from notebook node.", str(err))
+        sys.exit(1)
+
+
+# Main function for reconfiguring Spark for notebook
+@task
+def reconfigure_spark(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] + "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        subprocess.run("~/scripts/{}.py".format('notebook_reconfigure_spark'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed to reconfigure Spark for Notebook node.", str(err))
+        sys.exit(1)
+
+# Main function for checking inactivity status
+@task
+def check_inactivity(ctx):
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/" + os.environ['conf_resource'] + "/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        subprocess.run("~/scripts/{}.py".format('notebook_inactivity_check'), shell=True, check=True)
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed to check inactivity status.", str(err))
+        sys.exit(1)
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/tensor-jupyterlab/scripts/configure_tensor-jupyterlab_node.py b/infrastructure-provisioning/src/tensor-jupyterlab/scripts/configure_tensor-jupyterlab_node.py
new file mode 100644
index 0000000..4f89661
--- /dev/null
+++ b/infrastructure-provisioning/src/tensor-jupyterlab/scripts/configure_tensor-jupyterlab_node.py
@@ -0,0 +1,170 @@
+#!/usr/bin/python3
+
+# *****************************************************************************
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+# ******************************************************************************
+
+import argparse
+import os
+import sys
+from datalab.actions_lib import *
+from datalab.common_lib import *
+from datalab.fab import *
+from datalab.notebook_lib import *
+from fabric import *
+from patchwork.files import exists
+from patchwork import files
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--hostname', type=str, default='')
+parser.add_argument('--keyfile', type=str, default='')
+parser.add_argument('--region', type=str, default='')
+parser.add_argument('--os_user', type=str, default='')
+parser.add_argument('--ip_address', type=str, default='')
+parser.add_argument('--exploratory_name', type=str, default='')
+parser.add_argument('--edge_ip', type=str, default='')
+args = parser.parse_args()
+
+spark_version = os.environ['notebook_spark_version']
+hadoop_version = os.environ['notebook_hadoop_version']
+tensorflow_version = os.environ['notebook_tensorflow_version']
+jupyterlab_version = os.environ['notebook_jupyterlab_version']
+nvidia_version = os.environ['notebook_nvidia_version']
+theano_version = os.environ['notebook_theano_version']
+keras_version = os.environ['notebook_keras_version']
+python_venv_version = os.environ['notebook_python_venv_version']
+python_venv_path = '/opt/python/python{0}/bin/python{1}'.format(python_venv_version, python_venv_version[:3])
+if args.region == 'cn-north-1':
+    spark_link = "http://mirrors.hust.edu.cn/apache/spark/spark-" + spark_version + "/spark-" + spark_version + \
+                 "-bin-hadoop" + hadoop_version + ".tgz"
+else:
+    spark_link = "https://archive.apache.org/dist/spark/spark-" + spark_version + "/spark-" + spark_version + \
+                 "-bin-hadoop" + hadoop_version + ".tgz"
+pyspark_local_path_dir = '/home/' + args.os_user + '/.local/share/jupyter/kernels/pyspark_local/'
+py3spark_local_path_dir = '/home/' + args.os_user + '/.local/share/jupyter/kernels/py3spark_local/'
+local_spark_path = '/opt/spark/'
+jars_dir = '/opt/jars/'
+templates_dir = '/root/templates/'
+files_dir = '/root/files/'
+jupyterlab_conf_file = '/home/' + args.os_user + '/.jupyter/jupyter_lab_config.py'
+
+#
+gitlab_certfile = os.environ['conf_gitlab_certfile']
+cuda_version = os.environ['notebook_cuda_version']
+cuda_file_name = os.environ['notebook_cuda_file_name']
+cudnn_version = os.environ['notebook_cudnn_version']
+cudnn_file_name = os.environ['notebook_cudnn_file_name']
+venv_libs = "numpy scipy matplotlib pandas scikit-learn opencv-python tensorflow=={0}".format(tensorflow_version) # tflite==2.4.0 python3-opencv
+jupyterlab_pip = 'jupyterlab'
+
+##############
+# Run script #
+##############
+if __name__ == "__main__":
+    print("Configure connections")
+    global conn
+    conn = datalab.fab.init_datalab_connection(args.hostname, args.os_user, args.keyfile)
+
+    # PREPARE DISK
+    print("Prepare .ensure directory")
+    try:
+        if not exists(conn,'/home/' + args.os_user + '/.ensure_dir'):
+            conn.sudo('mkdir /home/' + args.os_user + '/.ensure_dir')
+    except:
+        sys.exit(1)
+    print("Mount additional volume")
+    prepare_disk(args.os_user)
+
+    # INSTALL LANGUAGES
+    print("Install Java")
+    ensure_jre_jdk(args.os_user)
+    print("Install Python 3 modules")
+    ensure_python3_libraries(args.os_user)
+
+    # INSTALL PYTHON IN VIRTUALENV
+    print("Configure Python Virtualenv")
+    ensure_python_venv(python_venv_version)
+
+    # INSTALL TENSORFLOW AND OTHER DEEP LEARNING LIBRARIES
+    #print("Install TensorFlow")
+    #install_tensor(args.os_user, cuda_version, cuda_file_name,
+    #               cudnn_version, cudnn_file_name, tensorflow_version,
+    #               templates_dir, nvidia_version)
+    print("Install Theano")
+    install_theano(args.os_user, theano_version)
+    print("Installing Keras")
+    install_keras(args.os_user, keras_version)
+
+    # INSTALL JUPYTER NOTEBOOK
+    print("Configure jupyterlab with tensorflow,tflite")
+    configure_jupyterlab(args.os_user, jupyterlab_conf_file, templates_dir, jupyterlab_version, args.exploratory_name)
+
+    #print("Install Jupyter")
+    #configure_jupyterlab(args.os_user, jupyterlab_conf_file, templates_dir, jupyterlab_version, args.exploratory_name)
+
+    # INSTALL SPARK AND CLOUD STORAGE JARS FOR SPARK
+    print("Install local Spark")
+    ensure_local_spark(args.os_user, spark_link, spark_version, hadoop_version, local_spark_path )
+    print("Install storage jars")
+    ensure_local_jars(args.os_user, jars_dir)
+    print("Configure local Spark")
+    configure_local_spark(jars_dir, templates_dir)
+
+    # INSTALL JUPYTER KERNELS
+    #print("Install pyspark local kernel for Jupyter")
+    #ensure_pyspark_local_kernel(args.os_user, pyspark_local_path_dir, templates_dir, spark_version)
+    print("Install py3spark local kernel for Jupyter")
+    ensure_py3spark_local_kernel(args.os_user, py3spark_local_path_dir, templates_dir, spark_version, python_venv_path, python_venv_version)
+
+    # INSTALL UNGIT
+    print("Install nodejs")
+    install_nodejs(args.os_user)
+    print("Install Ungit")
+    install_ungit(args.os_user, args.exploratory_name, args.edge_ip)
+    if exists(conn, '/home/{0}/{1}'.format(args.os_user, gitlab_certfile)):
+        install_gitlab_cert(args.os_user, gitlab_certfile)
+
+    # INSTALL INACTIVITY CHECKER
+    print("Install inactivity checker")
+    install_inactivity_checker(args.os_user, args.ip_address)
+
+    # INSTALL OPTIONAL PACKAGES
+    print("Installing additional Python packages")
+    ensure_additional_python_libs(args.os_user)
+    if os.environ['conf_cloud_provider'] == 'aws':
+        print('Installing Pytorch')
+        ensure_pytorch(args.os_user)
+    print("Install Matplotlib")
+    ensure_matplot(args.os_user)
+
+    print("Install python venv required libs")
+    ensure_venv_libs(args.os_user, venv_libs)
+    datalab.fab.install_venv_pip_pkg('--extra-index-url https://google-coral.github.io/py-repo/ tflite_runtime==2.5.0')
+    #ensure_venv_libs(args.os_user, '--extra-index-url https://google-coral.github.io/py-repo/ tflite_runtime==2.5.0')
+
+
+    #POST INSTALLATION PROCESS
+    print("Updating pyOpenSSL library")
+    update_pyopenssl_lib(args.os_user)
+
+    print("Removing unexisting kernels")
+    remove_unexisting_kernel(args.os_user)
+
+    conn.close()
diff --git a/infrastructure-provisioning/src/tensor/scripts/configure_tensor_node.py b/infrastructure-provisioning/src/tensor/scripts/configure_tensor_node.py
index c9b5e3f..021c400 100644
--- a/infrastructure-provisioning/src/tensor/scripts/configure_tensor_node.py
+++ b/infrastructure-provisioning/src/tensor/scripts/configure_tensor_node.py
@@ -9,9 +9,9 @@
 # to you under the Apache License, Version 2.0 (the
 # "License"); you may not use this file except in compliance
 # with the License.  You may obtain a copy of the License at
-# 
+#
 #   http://www.apache.org/licenses/LICENSE-2.0
-# 
+#
 # Unless required by applicable law or agreed to in writing,
 # software distributed under the License is distributed on an
 # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -69,7 +69,7 @@
 cuda_file_name = os.environ['notebook_cuda_file_name']
 cudnn_version = os.environ['notebook_cudnn_version']
 cudnn_file_name = os.environ['notebook_cudnn_file_name']
-
+venv_libs = "numpy scipy matplotlib pandas scikit-learn opencv-python tensorflow=={0}".format(tensorflow_version)
 
 ##############
 # Run script #
@@ -142,11 +142,19 @@
     # INSTALL OPTIONAL PACKAGES
     print("Installing additional Python packages")
     ensure_additional_python_libs(args.os_user)
+    print('Installing Pytorch')
+    ensure_pytorch(args.os_user)
     print("Install Matplotlib")
     ensure_matplot(args.os_user)
-    
+
+    print("Install python venv required libs")
+    ensure_venv_libs(args.os_user, venv_libs)
+    datalab.fab.install_venv_pip_pkg('--extra-index-url https://google-coral.github.io/py-repo/ tflite_runtime==2.5.0')
+
     #POST INSTALLATION PROCESS
     print("Updating pyOpenSSL library")
     update_pyopenssl_lib(args.os_user)
+    print("Removing unexisting kernels")
+    remove_unexisting_kernel(args.os_user)
 
     conn.close()
diff --git a/infrastructure-provisioning/src/zeppelin/scripts/configure_zeppelin_node.py b/infrastructure-provisioning/src/zeppelin/scripts/configure_zeppelin_node.py
index 868b289..a26273e 100644
--- a/infrastructure-provisioning/src/zeppelin/scripts/configure_zeppelin_node.py
+++ b/infrastructure-provisioning/src/zeppelin/scripts/configure_zeppelin_node.py
@@ -105,6 +105,7 @@
             conn.sudo('mkdir -p /opt/zeppelin/lib/interpreter/')
             conn.sudo('cp /opt/zeppelin/interpreter/md/zeppelin-markdown-*.jar /opt/zeppelin/lib/interpreter/')  # necessary when executing paragraph launches java process with "-cp :/opt/zeppelin/lib/interpreter/*:"
             conn.sudo('cp /opt/zeppelin/interpreter/sh/zeppelin-shell-*.jar /opt/zeppelin/lib/interpreter/')
+            conn.sudo('rm -r /opt/zeppelin/interpreter/python/')
         except Exception as err:
             print('Error:', str(err))
             sys.exit(1)
diff --git a/infrastructure-provisioning/terraform/aws/endpoint/main/bucket.tf b/infrastructure-provisioning/terraform/aws/endpoint/main/bucket.tf
index 86f70f0..307f908 100644
--- a/infrastructure-provisioning/terraform/aws/endpoint/main/bucket.tf
+++ b/infrastructure-provisioning/terraform/aws/endpoint/main/bucket.tf
@@ -25,7 +25,6 @@
 
 resource "aws_s3_bucket" "shared_bucket" {
   bucket = local.shared_s3_name
-  acl = "private"
   tags = {
     Name = local.shared_s3_name
      "${local.additional_tag[0]}"   = local.additional_tag[1]
@@ -34,4 +33,9 @@
      "endpoint_tag"                 = var.endpoint_id
    }
    force_destroy = true
- }
\ No newline at end of file
+ }
+
+resource "aws_s3_bucket_acl" "example_bucket_acl" {
+  bucket = aws_s3_bucket.shared_bucket.id
+  acl    = "private"
+  }
\ No newline at end of file
diff --git a/infrastructure-provisioning/terraform/aws/endpoint/main/instance.tf b/infrastructure-provisioning/terraform/aws/endpoint/main/instance.tf
index 6bfc09b..666ddad 100644
--- a/infrastructure-provisioning/terraform/aws/endpoint/main/instance.tf
+++ b/infrastructure-provisioning/terraform/aws/endpoint/main/instance.tf
@@ -28,7 +28,7 @@
   instance_type        = var.endpoint_instance_shape
   key_name             = var.key_name
   subnet_id            = data.aws_subnet.data_subnet.id
-  security_groups      = [aws_security_group.endpoint_sec_group.id]
+  security_groups      = [data.aws_security_group.data_sg.id]
   iam_instance_profile = aws_iam_instance_profile.endpoint_profile.name
   root_block_device {
     volume_type           = "gp2"
diff --git a/infrastructure-provisioning/terraform/aws/endpoint/main/network.tf b/infrastructure-provisioning/terraform/aws/endpoint/main/network.tf
index 1f0f96c..0fdb419 100644
--- a/infrastructure-provisioning/terraform/aws/endpoint/main/network.tf
+++ b/infrastructure-provisioning/terraform/aws/endpoint/main/network.tf
@@ -85,47 +85,48 @@
 
 resource "aws_security_group" "endpoint_sec_group" {
   name        = local.endpoint_sg_name
+  count       = var.sg_id == "" ? 1 : 0
   vpc_id      = data.aws_vpc.data_vpc.id
   ingress {
     from_port   = 22
     to_port     = 22
     protocol    = "tcp"
-    cidr_blocks = ["0.0.0.0/0"]
+    cidr_blocks = var.allowed_ip_cidrs
   }
 
   ingress {
     from_port   = 8084
     to_port     = 8084
     protocol    = "tcp"
-    cidr_blocks = ["0.0.0.0/0"]
+    cidr_blocks = var.allowed_ip_cidrs
   }
 
   ingress {
     from_port   = 8085
     to_port     = 8085
     protocol    = "tcp"
-    cidr_blocks = ["0.0.0.0/0"]
+    cidr_blocks = var.allowed_ip_cidrs
   }
 
   ingress {
     from_port   = 4822
     to_port     = 4822
     protocol    = "tcp"
-    cidr_blocks = ["0.0.0.0/0"]
+    cidr_blocks = var.allowed_ip_cidrs
   }
 
   ingress {
     from_port   = 8088
     to_port     = 8088
     protocol    = "tcp"
-    cidr_blocks = ["0.0.0.0/0"]
+    cidr_blocks = var.allowed_ip_cidrs
   }
 
     ingress {
     from_port   = 3128
     to_port     = 3128
     protocol    = "tcp"
-    cidr_blocks = ["0.0.0.0/0"]
+    cidr_blocks = var.allowed_ip_cidrs
   }
 
   egress {
@@ -143,6 +144,10 @@
   }
 }
 
+data "aws_security_group" "data_sg" {
+  id = var.sg_id == "" ? aws_security_group.endpoint_sec_group[1].id : var.sg_id
+}
+
 resource "aws_eip" "endpoint_eip" {
   vpc      = true
   tags = {
diff --git a/infrastructure-provisioning/terraform/aws/endpoint/main/outputs.tf b/infrastructure-provisioning/terraform/aws/endpoint/main/outputs.tf
index 4586fd2..f48560e 100644
--- a/infrastructure-provisioning/terraform/aws/endpoint/main/outputs.tf
+++ b/infrastructure-provisioning/terraform/aws/endpoint/main/outputs.tf
@@ -32,5 +32,5 @@
 }
 
 output "ssn_k8s_sg_id" {
-  value = aws_security_group.endpoint_sec_group.id
+  value = data.aws_security_group.data_sg.id
 }
\ No newline at end of file
diff --git a/infrastructure-provisioning/terraform/aws/endpoint/main/variables.tf b/infrastructure-provisioning/terraform/aws/endpoint/main/variables.tf
index 833afeb..9c89bcd 100644
--- a/infrastructure-provisioning/terraform/aws/endpoint/main/variables.tf
+++ b/infrastructure-provisioning/terraform/aws/endpoint/main/variables.tf
@@ -36,18 +36,27 @@
 
 variable "subnet_cidr" {}
 
+variable "allowed_ip_cidrs" {
+  type    = list(string)
+  default = ["0.0.0.0/0"]
+}
+
 variable "endpoint_instance_shape" {}
 
 variable "key_name" {}
 
 variable "ami" {
-  default = "ami-07b4f3c02c7f83d59"
+  default = "ami-07dd19a7900a1f049"
 }
 
 variable "vpc_id" {
   default = ""
 }
 
+variable "sg_id" {
+  default = ""
+}
+
 variable "subnet_id" {
   default = ""
 }
diff --git a/infrastructure-provisioning/terraform/aws/project/main/files/nb-policy.json b/infrastructure-provisioning/terraform/aws/project/main/files/nb-policy.json
new file mode 100644
index 0000000..bdc93c7
--- /dev/null
+++ b/infrastructure-provisioning/terraform/aws/project/main/files/nb-policy.json
@@ -0,0 +1,44 @@
+{
+    "Version": "2012-10-17",
+    "Statement": [
+        {
+            "Effect": "Allow",
+            "Action": "s3:ListAllMyBuckets",
+            "Resource": "arn:aws:s3:::*"
+        },
+        {
+            "Effect": "Allow",
+            "Action": [
+                "s3:ListBucket",
+                "s3:GetBucketLocation",
+                "s3:PutBucketPolicy",
+                "s3:PutEncryptionConfiguration"
+            ],
+            "Resource": [
+                "arn:aws:s3:::${sbn}*"
+            ]
+        },
+        {
+            "Effect": "Allow",
+            "Action": [
+                "s3:GetObject"
+            ],
+            "Resource": "arn:aws:s3:::${sbn}-ssn-bucket/*"
+        },
+        {
+            "Effect": "Allow",
+            "Action": [
+                "s3:Get*",
+                "s3:Delete*",
+                "s3:Put*",
+                "s3:ListBucket",
+                "s3:ListBucketMultipartUploads",
+                "s3:AbortMultipartUpload"
+            ],
+            "Resource": [
+                "arn:aws:s3:::${sbn}-bucket/*",
+                "arn:aws:s3:::${sbn}-shared-bucket/*"
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/infrastructure-provisioning/terraform/azure/endpoint/main/instance.tf b/infrastructure-provisioning/terraform/azure/endpoint/main/instance.tf
index 82c1497..f586725 100644
--- a/infrastructure-provisioning/terraform/azure/endpoint/main/instance.tf
+++ b/infrastructure-provisioning/terraform/azure/endpoint/main/instance.tf
@@ -37,9 +37,9 @@
   delete_os_disk_on_termination = true
 
   storage_image_reference {
-    publisher = element(split("_", var.ami),0)
-    offer     = element(split("_", var.ami),1)
-    sku       = element(split("_", var.ami),2)
+    publisher = element(split(":", var.ami),0)
+    offer     = element(split(":", var.ami),1)
+    sku       = element(split(":", var.ami),2)
     version   = "latest"
   }
   storage_os_disk {
diff --git a/infrastructure-provisioning/terraform/azure/endpoint/main/network.tf b/infrastructure-provisioning/terraform/azure/endpoint/main/network.tf
index 738f062..5ef2945 100644
--- a/infrastructure-provisioning/terraform/azure/endpoint/main/network.tf
+++ b/infrastructure-provisioning/terraform/azure/endpoint/main/network.tf
@@ -52,7 +52,8 @@
   name                 = local.endpoint_subnet_name
   resource_group_name  = data.azurerm_resource_group.data-endpoint-resource-group.name
   virtual_network_name = data.azurerm_virtual_network.data-endpoint-network.name
-  address_prefix       = var.subnet_cidr
+  address_prefixes     = [var.subnet_cidr]
+  service_endpoints    = ["Microsoft.Storage"]
 }
 
 data "azurerm_subnet" "data-endpoint-subnet" {
diff --git a/infrastructure-provisioning/terraform/azure/endpoint/main/sg.tf b/infrastructure-provisioning/terraform/azure/endpoint/main/sg.tf
index 08984f3..3140990 100644
--- a/infrastructure-provisioning/terraform/azure/endpoint/main/sg.tf
+++ b/infrastructure-provisioning/terraform/azure/endpoint/main/sg.tf
@@ -27,60 +27,28 @@
   location            = data.azurerm_resource_group.data-endpoint-resource-group.location
   resource_group_name = data.azurerm_resource_group.data-endpoint-resource-group.name
   name                = local.endpoint_sg_name
-}
 
-resource "azurerm_network_security_rule" "inbound-1" {
-  resource_group_name         = data.azurerm_resource_group.data-endpoint-resource-group.name
-  network_security_group_name = azurerm_network_security_group.enpoint-sg.name
-  name                        = "inbound-1"
-  direction                   = "Inbound"
-  access                      = "Allow"
-  priority                    = 100
-  source_address_prefix       = "*"
-  source_port_range           = "*"
-  destination_address_prefix  = "*"
-  destination_port_range      = "22"
-  protocol                    = "TCP"
-}
+  security_rule {
+    name                         = "AllowTCPInbound"
+    priority                     = 100
+    direction                    = "Inbound"
+    access                       = "Allow"
+    protocol                     = "Tcp"
+    source_port_range            = "*"
+    destination_port_ranges      = ["22", "8084", "8088"]
+    source_address_prefixes      = var.allowed_ip_cidrs
+    destination_address_prefix   = "*"
+  }
 
-resource "azurerm_network_security_rule" "inbound-2" {
-  resource_group_name         = data.azurerm_resource_group.data-endpoint-resource-group.name
-  network_security_group_name = azurerm_network_security_group.enpoint-sg.name
-  name                        = "inbound-2"
-  direction                   = "Inbound"
-  access                      = "Allow"
-  priority                    = 200
-  source_address_prefix       = "*"
-  source_port_range           = "*"
-  destination_address_prefix  = "*"
-  destination_port_range      = "8084"
-  protocol                    = "TCP"
-}
-
-resource "azurerm_network_security_rule" "inbound-3" {
-  resource_group_name         = data.azurerm_resource_group.data-endpoint-resource-group.name
-  network_security_group_name = azurerm_network_security_group.enpoint-sg.name
-  name                        = "inbound-3"
-  direction                   = "Inbound"
-  access                      = "Allow"
-  priority                    = 300
-  source_address_prefix       = "*"
-  source_port_range           = "*"
-  destination_address_prefix  = "*"
-  destination_port_range      = "8088"
-  protocol                    = "TCP"
-}
-
-resource "azurerm_network_security_rule" "outbound-1" {
-  resource_group_name         = data.azurerm_resource_group.data-endpoint-resource-group.name
-  network_security_group_name = azurerm_network_security_group.enpoint-sg.name
-  name                        = "outbound-1"
-  direction                   = "Outbound"
-  access                      = "Allow"
-  priority                    = 100
-  source_address_prefix       = "*"
-  source_port_range           = "*"
-  destination_address_prefix  = "*"
-  destination_port_range      = "*"
-  protocol                    = "*"
+  security_rule {
+    name                         = "AllowOutbound"
+    priority                     = 100
+    direction                    = "Outbound"
+    access                       = "Allow"
+    protocol                     = "*"
+    source_port_range            = "*"
+    destination_port_range       = "*"
+    source_address_prefix        = "*"
+    destination_address_prefix   = "*"
+  }
 }
diff --git a/infrastructure-provisioning/terraform/azure/endpoint/main/variables.tf b/infrastructure-provisioning/terraform/azure/endpoint/main/variables.tf
index e250793..5cfdb00 100644
--- a/infrastructure-provisioning/terraform/azure/endpoint/main/variables.tf
+++ b/infrastructure-provisioning/terraform/azure/endpoint/main/variables.tf
@@ -51,12 +51,17 @@
   default = ""
 }
 
+variable "allowed_ip_cidrs" {
+  type    = list(string)
+  default = ["0.0.0.0/0"]
+}
+
 variable "subnet_cidr" {}
 
 variable "endpoint_shape" {}
 
 variable "ami" {
-  default = "Canonical_UbuntuServer_16.04-LTS"
+  default = "Canonical:0001-com-ubuntu-server-focal:20_04-lts"
 }
 
 variable "endpoint_volume_size" {}
diff --git a/infrastructure-provisioning/terraform/bin/datalab.py b/infrastructure-provisioning/terraform/bin/datalab.py
index ff6c9f3..9ca39b2 100644
--- a/infrastructure-provisioning/terraform/bin/datalab.py
+++ b/infrastructure-provisioning/terraform/bin/datalab.py
@@ -191,17 +191,18 @@
         Returns:
             str: command result
         """
-        process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE,
-                                   stderr=subprocess.STDOUT,
-                                   universal_newlines=True)
+        # process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE,
+        #                            stderr=subprocess.STDOUT,
+        #                            universal_newlines=True)
+        subprocess.run(command, shell=True, check=True)
 
-        while True:
-            nextline = process.stdout.readline()
-            print(nextline)
-            if nextline == '' and process.poll() is not None:
-                break
-            if 'error' in nextline.lower():
-                sys.exit(0)
+        # while True:
+        #     nextline = process.stdout.readline()
+        #     print(nextline)
+        #     if nextline == '' and process.poll() is not None:
+        #         break
+        #     if 'error' in nextline.lower():
+        #         sys.exit(0)
 
     @staticmethod
     def execute(command):
@@ -1014,6 +1015,8 @@
                   default='false')
          .add_str('--billing_aws_account_id', 'The ID of ASW linked account', group='endpoint', default='')
          .add_str('--billing_tag', 'Billing tag', group='endpoint', default='datalab')
+         .add_str('--allowed_ip_cidrs', 'Allowed IP CIDRs for SGs', group='endpoint', default='["0.0.0.0/0"]')
+         .add_str('--sg_id', 'SG ID to be added to instance', group='endpoint', default="")
          )
         return params.build()
 
@@ -1191,8 +1194,8 @@
          .add_str('--ldap_user', 'ldap user', required=True, group='endpoint')
          .add_str('--ldap_bind_creds', 'ldap bind creds', required=True, group='endpoint')
          .add_str('--ldap_users_group', 'ldap users group', required=True, group='endpoint')
-         .add_str('--firewall_ing_cidr_range', 'Ingress range', group='endpoint')
-         .add_str('--firewall_eg_cidr_range', 'Egress range', group='endpoint')
+         .add_str('--firewall_ing_cidr_range', 'Ingress range', group='endpoint', default = '["0.0.0.0/0"]')
+         .add_str('--firewall_eg_cidr_range', 'Egress range', group='endpoint', default = '["0.0.0.0/0"]')
          .add_str('--endpoint_policies', 'Endpoint policies list', group='endpoint')
          .add_str('--endpoint_roles', 'Endpoint roles list', group='endpoint')
          .add_str('--bucket_region', 'Bucket region', group='endpoint')
@@ -1274,6 +1277,7 @@
          .add_str('--region_info', 'Azure region info', group='endpoint', default='')
          .add_str('--mongo_password', 'Mongo database password', group='endpoint')
          .add_str('--mongo_host', 'Mongo database host', group='endpoint', default='localhost')
+         .add_str('--allowed_ip_cidrs', 'Allowed IP CIDRs for SGs', group='endpoint', default='["0.0.0.0/0"]')
          .add_bool('--billing_enable', 'Billing enable', group='endpoint', default=False)
          )
         return params.build()
diff --git a/infrastructure-provisioning/terraform/bin/deploy/billing_app_aws.yml b/infrastructure-provisioning/terraform/bin/deploy/billing_app_aws.yml
index d523554..b6eaae3 100644
--- a/infrastructure-provisioning/terraform/bin/deploy/billing_app_aws.yml
+++ b/infrastructure-provisioning/terraform/bin/deploy/billing_app_aws.yml
@@ -48,7 +48,7 @@
 
 keycloak:
   bearer-only: true
-  realm: datalab
+  realm: KEYCLOAK_REALM_NAME
   resource: KEYCLOAK_CLIENT_ID
   credentials.secret: CLIENT_SECRET
   ssl-required: none
diff --git a/infrastructure-provisioning/terraform/bin/deploy/billing_azure.yml b/infrastructure-provisioning/terraform/bin/deploy/billing_azure.yml
index ac1ce50..8cdcd73 100644
--- a/infrastructure-provisioning/terraform/bin/deploy/billing_azure.yml
+++ b/infrastructure-provisioning/terraform/bin/deploy/billing_azure.yml
@@ -48,7 +48,7 @@
 
 keycloak:
   bearer-only: true
-  realm: datalab
+  realm: KEYCLOAK_REALM_NAME
   resource: KEYCLOAK_CLIENT_ID
   credentials.secret: KEYCLOAK_CLIENT_SECRET
   ssl-required: none
diff --git a/infrastructure-provisioning/terraform/bin/deploy/billing_gcp.yml b/infrastructure-provisioning/terraform/bin/deploy/billing_gcp.yml
index 454bf0a..9b19d02 100644
--- a/infrastructure-provisioning/terraform/bin/deploy/billing_gcp.yml
+++ b/infrastructure-provisioning/terraform/bin/deploy/billing_gcp.yml
@@ -52,7 +52,7 @@
 
 keycloak:
   bearer-only: true
-  realm: datalab
+  realm: KEYCLOAK_REALM_NAME
   resource: KEYCLOAK_CLIENT_ID
   credentials.secret: CLIENT_SECRET
   ssl-required: none
diff --git a/infrastructure-provisioning/terraform/bin/deploy/endpoint_fab.py b/infrastructure-provisioning/terraform/bin/deploy/endpoint_fab.py
index e5bd059..eafacc2 100644
--- a/infrastructure-provisioning/terraform/bin/deploy/endpoint_fab.py
+++ b/infrastructure-provisioning/terraform/bin/deploy/endpoint_fab.py
@@ -247,8 +247,12 @@
                                            "| grep 'DNS Servers:' "
                                            "| awk '{print $3}'")
                                   .stdout.rstrip("\n\r"))
-                conn.sudo("sed -i 's|DNS_IP_RESOLVE|\"dns\": [\"{0}\"],|g' {1}/tmp/daemon.json"
+                if dns_ip_resolve:
+                    conn.sudo("sed -i 's|DNS_IP_RESOLVE|\"dns\": [\"{0}\"],|g' {1}/tmp/daemon.json"
                           .format(dns_ip_resolve, args.datalab_path))
+                else:
+                    conn.sudo("sed -i 's|DNS_IP_RESOLVE||g' {}/tmp/daemon.json"
+                              .format(args.datalab_path))
             elif args.cloud_provider == "gcp" or args.cloud_provider == "azure":
                 dns_ip_resolve = ""
                 conn.sudo('sed -i "s|DNS_IP_RESOLVE||g" {1}/tmp/daemon.json'
@@ -270,10 +274,8 @@
     try:
         print('[INSTALLING MONGO DATABASE]')
         if not exists(conn, '/home/{}/.ensure_dir/mongo_ensured'.format(args.os_user)):
-            conn.sudo("bash -c 'wget -qO - https://www.mongodb.org/static/pgp/server-4.2.asc | sudo apt-key add -'")
-            conn.sudo("bash -c 'echo \"deb [ arch=amd64,arm64 ] "
-                      "https://repo.mongodb.org/apt/ubuntu $(lsb_release -cs)/mongodb-org/4.2 multiverse\" | sudo "
-                      "tee /etc/apt/sources.list.d/mongodb-org-4.2.list'")
+            conn.sudo("bash -c 'wget -qO - https://www.mongodb.org/static/pgp/server-4.4.asc | sudo apt-key add -'")
+            conn.sudo("bash -c 'echo \"deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu $(lsb_release -cs)/mongodb-org/4.4 multiverse\" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.4.list'")
             conn.sudo('apt-get update')
             conn.sudo('apt-get -y --allow-unauthenticated install mongodb-org')
             conn.sudo('systemctl enable mongod.service')
@@ -639,8 +641,8 @@
         if not exists(conn, ensure_file):
             list_images = {
                 'aws': ['base', 'edge', 'project', 'jupyter', 'rstudio', 'zeppelin', 'tensor', 'tensor-rstudio',
-                        'deeplearning', 'jupyterlab', 'dataengine-service', 'dataengine'],
-                'gcp': ['base', 'edge', 'project', 'jupyter', 'rstudio', 'zeppelin', 'tensor', 'tensor-rstudio',
+                        'tensor-jupyterlab', 'deeplearning', 'jupyterlab', 'dataengine-service', 'dataengine'],
+                'gcp': ['base', 'edge', 'project', 'jupyter', 'jupyter-gpu', 'rstudio', 'zeppelin', 'tensor', 'tensor-rstudio',
                         'deeplearning', 'superset', 'jupyterlab', 'dataengine-service', 'dataengine'],
                 'azure': ['base', 'edge', 'project', 'jupyter', 'rstudio', 'zeppelin', 'tensor', 'deeplearning',
                           'dataengine']
@@ -658,8 +660,7 @@
                           .format(args.repository_address, args.repository_port, args.cloud_provider, image))
                 conn.sudo('docker rmi {0}:{1}/docker.datalab-{3}-{2}'
                           .format(args.repository_address, args.repository_port, args.cloud_provider, image))
-            conn.sudo('chown -R {0}:docker /home/{0}/.docker/'
-                      .format(args.os_user))
+            #conn.sudo('chown -R {0}:docker /home/{0}/.docker/'.format(args.os_user))
             conn.sudo('touch {}'.format(ensure_file))
     except Exception as err:
         logging.error('Failed to pull Docker images: ', str(err))
@@ -675,7 +676,7 @@
     try:
         mysql_pass = id_generator()
         conn.sudo('docker run --name guacd --restart unless-stopped -d -p 4822:4822 guacamole/guacd')
-        conn.sudo('docker run --rm guacamole/guacamole /opt/guacamole/bin/initdb.sh --mysql > initdb.sql')
+        conn.sudo('docker run --rm guacamole/guacamole:1.4.0 /opt/guacamole/bin/initdb.sh --mysql > initdb.sql')
         conn.sudo('mkdir /tmp/scripts')
         conn.sudo('cp initdb.sql /tmp/scripts')
         conn.sudo('mkdir -p /opt/mysql')
@@ -693,7 +694,7 @@
                   .format(mysql_pass))
         conn.sudo("docker run --name guacamole --restart unless-stopped --link guacd:guacd --link guac-mysql:mysql"
                   " -e MYSQL_DATABASE='guacamole' -e MYSQL_USER='guacamole' -e MYSQL_PASSWORD='{}'"
-                  " -d -p 8080:8080 guacamole/guacamole".format(mysql_pass))
+                  " -d -p 8080:8080 guacamole/guacamole:1.4.0".format(mysql_pass))
         # create cronjob for run containers on reboot
         conn.sudo('mkdir -p /opt/datalab/cron')
         conn.sudo('touch /opt/datalab/cron/mysql.sh')
@@ -704,7 +705,7 @@
         conn.sudo('echo "docker rm guacamole" >> /opt/datalab/cron/mysql.sh')
         conn.sudo("""echo "docker run --name guacamole --restart unless-stopped --link guacd:guacd"""
                   """ --link guac-mysql:mysql -e MYSQL_DATABASE='guacamole' -e MYSQL_USER='guacamole' """
-                  """-e MYSQL_PASSWORD='{}' -d -p 8080:8080 guacamole/guacamole" >> """
+                  """-e MYSQL_PASSWORD='{}' -d -p 8080:8080 guacamole/guacamole:1.4.0" >> """
                   """/opt/datalab/cron/mysql.sh""".format(mysql_pass))
         conn.sudo('''/bin/bash -c '(crontab -l 2>/dev/null; echo "@reboot sh /opt/datalab/cron/mysql.sh") |'''
                   ''' crontab - ' ''')
@@ -989,7 +990,7 @@
     parser.add_argument('--repository_user', type=str, default='')
     parser.add_argument('--repository_pass', type=str, default='')
     parser.add_argument('--release_tag', type=str,
-                        default='2.5.1')
+                        default='2.6.0')
     parser.add_argument('--docker_version', type=str,
                         default='5:20.10.6~3-0~ubuntu-bionic')
     parser.add_argument('--ssn_bucket_name', type=str, default='')
diff --git a/infrastructure-provisioning/terraform/gcp/endpoint/main/bucket.tf b/infrastructure-provisioning/terraform/gcp/endpoint/main/bucket.tf
index 9551d65..2328deb 100644
--- a/infrastructure-provisioning/terraform/gcp/endpoint/main/bucket.tf
+++ b/infrastructure-provisioning/terraform/gcp/endpoint/main/bucket.tf
@@ -27,6 +27,7 @@
  resource "google_storage_bucket" "shared_bucket" {
    name     = local.shared_bucket_name
    force_destroy = true
+   location = var.region
    labels = {
      name                              = local.shared_bucket_name
      "${local.additional_tag[0]}"      = local.additional_tag[1]
diff --git a/infrastructure-provisioning/terraform/gcp/endpoint/main/iam.tf b/infrastructure-provisioning/terraform/gcp/endpoint/main/iam.tf
index eda7eb5..c10dcff 100644
--- a/infrastructure-provisioning/terraform/gcp/endpoint/main/iam.tf
+++ b/infrastructure-provisioning/terraform/gcp/endpoint/main/iam.tf
@@ -38,12 +38,14 @@
 
 resource "google_project_iam_member" "iam" {
   # try to set perms as file
+  project = var.gcp_project_id
   count  = length(var.endpoint_roles)
   member = "serviceAccount:${google_service_account.endpoint_sa.email}"
   role   = element(var.endpoint_roles, count.index)
 }
 
 resource "google_project_iam_member" "role_for_member" {
+  project = var.gcp_project_id
   member = "serviceAccount:${google_service_account.endpoint_sa.email}"
   role   = google_project_iam_custom_role.endpoint_role.id
 }
diff --git a/infrastructure-provisioning/terraform/gcp/endpoint/main/network.tf b/infrastructure-provisioning/terraform/gcp/endpoint/main/network.tf
index 65becf8..752e55d 100644
--- a/infrastructure-provisioning/terraform/gcp/endpoint/main/network.tf
+++ b/infrastructure-provisioning/terraform/gcp/endpoint/main/network.tf
@@ -56,7 +56,7 @@
     ports    = ["22", "8084", "8085", "4822", "8088"]
   }
   target_tags   = ["${var.service_base_name}-${var.endpoint_id}-endpoint"]
-  source_ranges = [var.firewall_ing_cidr_range]
+  source_ranges = var.firewall_ing_cidr_range
 
 }
 
@@ -68,5 +68,5 @@
     protocol = "all"
   }
   target_tags        = ["${var.service_base_name}-${var.endpoint_id}-endpoint"]
-  destination_ranges = [var.firewall_eg_cidr_range]
+  destination_ranges = var.firewall_eg_cidr_range
 }
diff --git a/infrastructure-provisioning/terraform/gcp/endpoint/main/variables.tf b/infrastructure-provisioning/terraform/gcp/endpoint/main/variables.tf
index aa42396..e8ac647 100644
--- a/infrastructure-provisioning/terraform/gcp/endpoint/main/variables.tf
+++ b/infrastructure-provisioning/terraform/gcp/endpoint/main/variables.tf
@@ -52,7 +52,7 @@
 }
 
 variable "ami" {
-  default = "/projects/ubuntu-os-cloud/global/images/ubuntu-1604-xenial-v20190628"
+  default = "/projects/ubuntu-os-cloud/global/images/ubuntu-2004-focal-v20210119a"
 }
 
 variable "subnet_id" {
@@ -68,15 +68,17 @@
 }
 
 variable "firewall_ing_cidr_range" {
-  default = "0.0.0.0/0"
+  type = list(string)
+  default = ["0.0.0.0/0"]
 }
 
 variable "firewall_eg_cidr_range" {
-  default = "0.0.0.0/0"
+  type = list(string)
+  default = ["0.0.0.0/0"]
 }
 
 variable "endpoint_policies" {
-  type = "list"
+  type = list(string)
   default = [
     "storage.buckets.create",
     "storage.buckets.delete",
@@ -121,7 +123,7 @@
 }
 
 variable "endpoint_roles" {
-  type = "list"
+  type = list(string)
   default = [
     "roles/iam.serviceAccountUser",
     "roles/iam.serviceAccountAdmin",
diff --git a/infrastructure-provisioning/terraform/gcp/endpoint/provisioning.py b/infrastructure-provisioning/terraform/gcp/endpoint/provisioning.py
index ed83bb6..b8305e6 100644
--- a/infrastructure-provisioning/terraform/gcp/endpoint/provisioning.py
+++ b/infrastructure-provisioning/terraform/gcp/endpoint/provisioning.py
@@ -402,6 +402,8 @@
                       .format(args.repository_address, args.repository_port, args.cloud_provider))
             conn.sudo('docker pull {}:{}/docker.datalab-jupyter-{}'
                       .format(args.repository_address, args.repository_port, args.cloud_provider))
+            conn.sudo('docker pull {}:{}/docker.datalab-jupyter-gpu-{}'
+                      .format(args.repository_address, args.repository_port, args.cloud_provider))
             conn.sudo('docker pull {}:{}/docker.datalab-rstudio-{}'
                       .format(args.repository_address, args.repository_port, args.cloud_provider))
             conn.sudo('docker pull {}:{}/docker.datalab-zeppelin-{}'
@@ -410,6 +412,8 @@
                       .format(args.repository_address, args.repository_port, args.cloud_provider))
             conn.sudo('docker pull {}:{}/docker.datalab-tensor-rstudio-{}'
                       .format(args.repository_address, args.repository_port, args.cloud_provider))
+            conn.sudo('docker pull {}:{}/docker.datalab-tensor-jupyterlab-{}'
+                      .format(args.repository_address, args.repository_port, args.cloud_provider))
             conn.sudo('docker pull {}:{}/docker.datalab-deeplearning-{}'
                       .format(args.repository_address, args.repository_port, args.cloud_provider))
             conn.sudo('docker pull {}:{}/docker.datalab-dataengine-service-{}'
@@ -434,6 +438,9 @@
             conn.sudo('docker tag {}:{}/docker.datalab-tensor-rstudio-{} '
                       'docker.datalab-tensor-rstudio'
                       .format(args.repository_address, args.repository_port, args.cloud_provider))
+            conn.sudo('docker tag {}:{}/docker.datalab-tensor-jupyterlab-{} '
+                      'docker.datalab-tensor-jupyterlab'
+                      .format(args.repository_address, args.repository_port, args.cloud_provider))
             conn.sudo('docker tag {}:{}/docker.datalab-deeplearning-{} '
                       'docker.datalab-deeplearning'
                       .format(args.repository_address, args.repository_port, args.cloud_provider))
@@ -459,6 +466,8 @@
                       .format(args.repository_address, args.repository_port, args.cloud_provider))
             conn.sudo('docker rmi {}:{}/docker.datalab-tensor-rstudio-{}'
                       .format(args.repository_address, args.repository_port, args.cloud_provider))
+            conn.sudo('docker rmi {}:{}/docker.datalab-tensor-jupyterlab-{}'
+                      .format(args.repository_address, args.repository_port, args.cloud_provider))
             conn.sudo('docker rmi {}:{}/docker.datalab-deeplearning-{}'
                       .format(args.repository_address, args.repository_port, args.cloud_provider))
             conn.sudo('docker rmi {}:{}/docker.datalab-dataengine-service-{}'
diff --git a/infrastructure-provisioning/terraform/gcp/modules/common/iam.tf b/infrastructure-provisioning/terraform/gcp/modules/common/iam.tf
index d409a34..271cab3 100644
--- a/infrastructure-provisioning/terraform/gcp/modules/common/iam.tf
+++ b/infrastructure-provisioning/terraform/gcp/modules/common/iam.tf
@@ -45,6 +45,7 @@
 
 resource "google_project_iam_member" "role_for_member" {
   #Grant the custom role for the ps_sa
+  project = var.gcp_project_id
   member = "serviceAccount:${google_service_account.ps_sa.email}"
   role   = "${google_project_iam_custom_role.ps-custom-role.id}"
 }
@@ -52,6 +53,7 @@
 resource "google_project_iam_member" "iam" {
   #Grant other roles for the ps_sa
   count  = "${length(var.ps_roles)}"
+  project = var.gcp_project_id
   member = "serviceAccount:${google_service_account.ps_sa.email}"
   role   = "${element(var.ps_roles, count.index)}"
 }
\ No newline at end of file
diff --git a/infrastructure-provisioning/terraform/gcp/modules/common/variables.tf b/infrastructure-provisioning/terraform/gcp/modules/common/variables.tf
index ec812d0..f4d22dc 100644
--- a/infrastructure-provisioning/terraform/gcp/modules/common/variables.tf
+++ b/infrastructure-provisioning/terraform/gcp/modules/common/variables.tf
@@ -46,14 +46,14 @@
 variable "traefik_cidr" {}
 
 variable "ps_roles" {
-  type = "list"
+  type = list(string)
   default = [
     "roles/dataproc.worker"
   ]
 }
 
 variable "ps_policy" {
-  type = "list"
+  type = list(string)
   default = [
 
   ]
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 0000000..9b3caa4
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,6 @@
+{
+  "name": "incubator-datalab",
+  "lockfileVersion": 2,
+  "requires": true,
+  "packages": {}
+}
diff --git a/pom.xml b/pom.xml
index 2224ef8..dc845f0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -105,11 +105,13 @@
         <module>services/billing-azure</module>
         <module>services/billing-gcp</module>
         <module>services/billing-aws</module>
+        <module>services/self-service/src/main/resources/webapp</module>
+        <module>infrastructure-provisioning</module>
     </modules>
 
     <properties>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
-        <io.dropwizard.version>1.3.21</io.dropwizard.version>
+        <io.dropwizard.version>1.3.29</io.dropwizard.version>
         <dropwizard.swagger.version>1.3.5-1</dropwizard.swagger.version>
         <com.google.inject.version>4.2.0</com.google.inject.version>
         <dropwizard-template-config.version>1.4.0</dropwizard-template-config.version>
diff --git a/services/billing-aws/src/main/resources/application.yml b/services/billing-aws/src/main/resources/application.yml
index 7849fb7..fe04f21 100644
--- a/services/billing-aws/src/main/resources/application.yml
+++ b/services/billing-aws/src/main/resources/application.yml
@@ -48,7 +48,7 @@
 
 keycloak:
   bearer-only: true
-  realm: datalab
+  realm: KEYCLOAK_REALM_NAME
   resource: KEYCLOAK_CLIENT_ID
   credentials.secret: KEYCLOAK_CLIENT_SECRET
   ssl-required: none
diff --git a/services/billing-azure/pom.xml b/services/billing-azure/pom.xml
index b5a4098..4e69ebb 100644
--- a/services/billing-azure/pom.xml
+++ b/services/billing-azure/pom.xml
@@ -119,7 +119,7 @@
         <dependency>
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>httpclient</artifactId>
-            <version>4.5.5</version>
+            <version>4.5.13</version>
         </dependency>
 
 <!--        <dependency>-->
diff --git a/services/billing-azure/src/main/resources/application.yml b/services/billing-azure/src/main/resources/application.yml
index 60527a3..1e5acb7 100644
--- a/services/billing-azure/src/main/resources/application.yml
+++ b/services/billing-azure/src/main/resources/application.yml
@@ -48,7 +48,7 @@
 
 keycloak:
   bearer-only: true
-  realm: datalab
+  realm: KEYCLOAK_REALM_NAME
   resource: KEYCLOAK_CLIENT_ID
   credentials.secret: CLIENT_SECRET
   ssl-required: none
diff --git a/services/billing-gcp/src/main/resources/application.yml b/services/billing-gcp/src/main/resources/application.yml
index e491cd5..458cdd0 100644
--- a/services/billing-gcp/src/main/resources/application.yml
+++ b/services/billing-gcp/src/main/resources/application.yml
@@ -52,7 +52,7 @@
 
 keycloak:
   bearer-only: true
-  realm: datalab
+  realm: KEYCLOAK_REALM_NAME
   resource: KEYCLOAK_CLIENT_ID
   credentials.secret: CLIENT_SECRET
   ssl-required: none
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/SharedWith.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/SharedWith.java
new file mode 100644
index 0000000..711043f
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/SharedWith.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+import java.util.TreeSet;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class SharedWith {
+    private TreeSet<String> users = new TreeSet<>();
+    private TreeSet<String> groups = new TreeSet<>();
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/computational/AzureComputationalResource.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/computational/AzureComputationalResource.java
new file mode 100644
index 0000000..c97e9f0
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/computational/AzureComputationalResource.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.dto.azure.computational;
+
+import com.epam.datalab.dto.ResourceURL;
+import com.epam.datalab.dto.SchedulerJobDTO;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.dto.computational.UserComputationalResource;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+
+import java.time.LocalDateTime;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+@ToString(callSuper = true)
+@Getter
+@EqualsAndHashCode(callSuper = true)
+public class AzureComputationalResource extends UserComputationalResource {
+    @JsonProperty("instance_id")
+    private final String instanceId;
+    @JsonProperty("master_node_shape")
+    private final String masterShape;
+    @JsonProperty("slave_node_shape")
+    private final String slaveShape;
+    @JsonProperty("hdinsight_version")
+    private final String version;
+    @JsonProperty("hdinsight_slave_count")
+    private final String slaveInstanceCount;
+
+
+    @Builder
+    public AzureComputationalResource(String computationalName, String computationalId, String imageName,
+                                      String templateName, String status, Date uptime,
+                                      SchedulerJobDTO schedulerJobData, boolean reuploadKeyRequired,
+                                      String instanceId, String masterShape, String slaveShape, String version,
+                                      List<ResourceURL> resourceURL, LocalDateTime lastActivity,
+                                      List<ClusterConfig> config, Map<String, String> tags, int totalInstanceCount, String slaveInstanceCount) {
+        super(computationalName, computationalId, imageName, templateName, status, uptime, schedulerJobData,
+                reuploadKeyRequired, resourceURL, lastActivity, tags, totalInstanceCount);
+        this.instanceId = instanceId;
+        this.masterShape = masterShape;
+        this.slaveShape = slaveShape;
+        this.version = version;
+        this.slaveInstanceCount = slaveInstanceCount;
+        this.config = config;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/computational/AzureComputationalTerminateDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/computational/AzureComputationalTerminateDTO.java
new file mode 100644
index 0000000..b0e6d0e
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/computational/AzureComputationalTerminateDTO.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.dto.azure.computational;
+
+import com.epam.datalab.dto.computational.ComputationalTerminateDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+public class AzureComputationalTerminateDTO extends ComputationalTerminateDTO {
+
+    @JsonProperty("hdinsight_cluster_name")
+    private String clusterName;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/computational/ComputationalConfigAzure.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/computational/ComputationalConfigAzure.java
new file mode 100644
index 0000000..d9a47fd
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/computational/ComputationalConfigAzure.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.dto.azure.computational;
+
+public class ComputationalConfigAzure {
+    private String hdinsightversion;
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/computational/ComputationalCreateAzure.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/computational/ComputationalCreateAzure.java
new file mode 100644
index 0000000..561f004
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/azure/computational/ComputationalCreateAzure.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.dto.azure.computational;
+
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.dto.aws.computational.ComputationalCreateAws;
+import com.epam.datalab.dto.base.computational.ComputationalBase;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class ComputationalCreateAzure extends ComputationalBase<ComputationalCreateAzure> {
+    @JsonProperty("hdinsight_count")
+    private String instanceCount;
+    @JsonProperty("hdinsight_slave_count")
+    private String slaveInstanceCount;
+    @JsonProperty("hdinsight_master_instance_type")
+    private String masterInstanceType;
+    @JsonProperty("hdinsight_slave_instance_type")
+    private String slaveInstanceType;
+    @JsonProperty("hdinsight_version")
+    private String version;
+    @JsonProperty("config")
+    private List<ClusterConfig> config;
+    @JsonProperty("conf_shared_image_enabled")
+    private String sharedImageEnabled;
+
+    public String getInstanceCount() {
+        return instanceCount;
+    }
+
+    public void setInstanceCount(String instanceCount) {
+        this.instanceCount = instanceCount;
+    }
+
+    public ComputationalCreateAzure withInstanceCount(String instanceCount) {
+        setInstanceCount(instanceCount);
+        return this;
+    }
+
+    public ComputationalCreateAzure withMasterInstanceType(String masterInstanceType) {
+        setMasterInstanceType(masterInstanceType);
+        return this;
+    }
+
+    public ComputationalCreateAzure withSlaveInstanceType(String slaveInstanceType) {
+        setSlaveInstanceType(slaveInstanceType);
+        return this;
+    }
+
+    public ComputationalCreateAzure withVersion(String version) {
+        setVersion(version);
+        return this;
+    }
+
+    public ComputationalCreateAzure withConfig(List<ClusterConfig> config) {
+        setConfig(config);
+        return this;
+    }
+
+    public ComputationalCreateAzure withSharedImageEnabled(String sharedImageEnabled) {
+        setSharedImageEnabled(sharedImageEnabled);
+        return this;
+    }
+
+    public ComputationalCreateAzure withNotebookName(String name) {
+        setNotebookInstanceName(name);
+        return this;
+    }
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/UserComputationalResource.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/UserComputationalResource.java
index dbb35e2..17ac694 100644
--- a/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/UserComputationalResource.java
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/computational/UserComputationalResource.java
@@ -71,6 +71,8 @@
     private String gcpClusterVersion;
     @JsonProperty("emr_version")
     private String awsClusterVersion;
+    @JsonProperty("hdinsight_version")
+    private String azureClusterVersion;
     private int totalInstanceCount;
     protected List<ClusterConfig> config;
     private Map<String, String> tags;
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ImageSharingStatus.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ImageSharingStatus.java
new file mode 100644
index 0000000..13bd531
--- /dev/null
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ImageSharingStatus.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.dto.exploratory;
+
+public enum ImageSharingStatus {
+    PRIVATE,
+    SHARED,
+    RECEIVED
+
+}
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ImageStatus.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ImageStatus.java
index 90e3edf..80ec6f0 100644
--- a/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ImageStatus.java
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/exploratory/ImageStatus.java
@@ -25,7 +25,9 @@
 
 public enum ImageStatus {
     CREATING,
-    CREATED,
+    ACTIVE,
+    TERMINATING,
+    TERMINATED,
     FAILED;
 
     @JsonCreator
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/dto/project/ProjectCreateDTO.java b/services/datalab-model/src/main/java/com/epam/datalab/dto/project/ProjectCreateDTO.java
index c780d4d..1586f3f 100644
--- a/services/datalab-model/src/main/java/com/epam/datalab/dto/project/ProjectCreateDTO.java
+++ b/services/datalab-model/src/main/java/com/epam/datalab/dto/project/ProjectCreateDTO.java
@@ -25,7 +25,7 @@
 import lombok.Data;
 import lombok.EqualsAndHashCode;
 
-@EqualsAndHashCode(callSuper = true)
+@EqualsAndHashCode
 @Data
 @Builder
 public class ProjectCreateDTO extends ResourceBaseDTO<ProjectCreateDTO> {
diff --git a/services/datalab-model/src/main/java/com/epam/datalab/model/exploratory/Image.java b/services/datalab-model/src/main/java/com/epam/datalab/model/exploratory/Image.java
index c8d3b2c..3fd928b 100644
--- a/services/datalab-model/src/main/java/com/epam/datalab/model/exploratory/Image.java
+++ b/services/datalab-model/src/main/java/com/epam/datalab/model/exploratory/Image.java
@@ -19,6 +19,8 @@
 
 package com.epam.datalab.model.exploratory;
 
+import com.epam.datalab.dto.SharedWith;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
 import com.epam.datalab.dto.exploratory.ImageStatus;
 import com.epam.datalab.model.library.Library;
 import lombok.Builder;
@@ -40,7 +42,12 @@
     private final String fullName;
     private final String externalName;
     private final String application;
+    private final String templateName;
+    private final String instanceName;
+    private final String cloudProvider;
     private final String dockerImage;
+    private final SharedWith sharedWith;
+    private final List<ClusterConfig> clusterConfig;
     private final List<Library> libraries;
     private final Map<String, List<Library>> computationalLibraries;
 }
diff --git a/services/datalab-utils/src/test/java/com/epam/datalab/util/mongo/IsoLocalDateTimeSerDeTest.java b/services/datalab-utils/src/test/java/com/epam/datalab/util/mongo/IsoLocalDateTimeSerDeTest.java
index 391238a..108aaf2 100644
--- a/services/datalab-utils/src/test/java/com/epam/datalab/util/mongo/IsoLocalDateTimeSerDeTest.java
+++ b/services/datalab-utils/src/test/java/com/epam/datalab/util/mongo/IsoLocalDateTimeSerDeTest.java
@@ -29,6 +29,7 @@
 import java.io.IOException;
 import java.time.LocalDateTime;
 import java.time.ZoneId;
+import java.time.temporal.ChronoUnit;
 
 import static org.junit.Assert.assertEquals;
 
@@ -42,14 +43,14 @@
     }
 
     @Test
-    public void shoudProperlySerializeLocalDateTimeToJson() throws JsonProcessingException {
+    public void shouldProperlySerializeLocalDateTimeToJson() throws JsonProcessingException {
         String actual = objectMapper.writeValueAsString(new SampleClass());
         assertEquals("{\"localDateTime\":{\"$date\":\"2018-04-10T15:30:45\"}}", actual);
     }
 
     @Test
-    public void shoudProperlyDeserializeLocalDateTimeFromJson() throws IOException {
-        LocalDateTime now = LocalDateTime.now();
+    public void shouldProperlyDeserializeLocalDateTimeFromJson() throws IOException {
+        LocalDateTime now = LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS);
         long l = now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
         SampleClass actual = objectMapper
                 .readValue("{\"localDateTime\":{\"$date\":" + l + "}}", SampleClass.class);
diff --git a/services/datalab-webapp-common/pom.xml b/services/datalab-webapp-common/pom.xml
index b42da46..f965f04 100644
--- a/services/datalab-webapp-common/pom.xml
+++ b/services/datalab-webapp-common/pom.xml
@@ -68,7 +68,7 @@
         <dependency>
             <groupId>commons-io</groupId>
             <artifactId>commons-io</artifactId>
-            <version>2.4</version>
+            <version>2.7</version>
         </dependency>
     </dependencies>
 </project>
\ No newline at end of file
diff --git a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/ExploratoryAPI.java b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/ExploratoryAPI.java
index d153a15..bce4eb2 100644
--- a/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/ExploratoryAPI.java
+++ b/services/datalab-webapp-common/src/main/java/com/epam/datalab/rest/contracts/ExploratoryAPI.java
@@ -31,4 +31,5 @@
     String EXPLORATORY_LIB_LIST = LIBRARY + EXPLORATORY + "/lib_list";
     String EXPLORATORY_GIT_CREDS = EXPLORATORY + "/git_creds";
     String EXPLORATORY_IMAGE = EXPLORATORY + "/image";
+    String EXPLORATORY_IMAGE_TERMINATE = EXPLORATORY + "/image" + "/terminate";
 }
diff --git a/services/provisioning-service/pom.xml b/services/provisioning-service/pom.xml
index a6f16e9..c7c9804 100644
--- a/services/provisioning-service/pom.xml
+++ b/services/provisioning-service/pom.xml
@@ -106,7 +106,7 @@
         <dependency>
             <groupId>org.apache.httpcomponents</groupId>
             <artifactId>httpclient</artifactId>
-            <version>4.5.9</version>
+            <version>4.5.13</version>
         </dependency>
         <dependency>
             <groupId>com.azure</groupId>
@@ -139,7 +139,7 @@
         <dependency>
             <groupId>commons-io</groupId>
             <artifactId>commons-io</artifactId>
-            <version>2.6</version>
+            <version>2.7</version>
         </dependency>
         <dependency>
             <groupId>commons-fileupload</groupId>
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CommandExecutorMock.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CommandExecutorMock.java
index 33bd495..c8db9c3 100644
--- a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CommandExecutorMock.java
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/CommandExecutorMock.java
@@ -78,12 +78,14 @@
             List<String> list = Lists.newArrayList(
                     "docker.datalab-deeplearning:latest",
                     "docker.datalab-jupyter:latest",
+                    "docker.datalab-jupyter-gpu:latest",
                     "docker.datalab-jupyterlab:latest",
                     "docker.datalab-superset:latest",
                     "docker.datalab-rstudio:latest",
                     "docker.datalab-tensor:latest",
                     "docker.datalab-zeppelin:latest",
-                    "docker.datalab-tensor-rstudio:latest");
+                    "docker.datalab-tensor-rstudio:latest",
+                    "docker.datalab-tensor-jupyterlab:latest");
 
             list.addAll(getComputationalDockerImage());
 
@@ -103,7 +105,7 @@
             case AWS:
                 return Lists.newArrayList(DOCKER_DATALAB_DATAENGINE_SERVICE, DOCKER_DATALAB_DATAENGINE);
             case AZURE:
-                return Lists.newArrayList(DOCKER_DATALAB_DATAENGINE);
+                return Lists.newArrayList(DOCKER_DATALAB_DATAENGINE, DOCKER_DATALAB_DATAENGINE_SERVICE);
             case GCP:
                 return Lists.newArrayList(DOCKER_DATALAB_DATAENGINE_SERVICE, DOCKER_DATALAB_DATAENGINE);
             default:
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/DockerAction.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/DockerAction.java
index d61bac6..a801aef 100644
--- a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/DockerAction.java
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/commands/DockerAction.java
@@ -32,6 +32,7 @@
 	LIB_INSTALL,
 	GIT_CREDS,
 	CREATE_IMAGE,
+    TERMINATE_IMAGE,
 	STATUS,
     REUPLOAD_KEY,
     RECONFIGURE_SPARK,
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ComputationalConfigure.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ComputationalConfigure.java
index 3cdfcf2..21c11eb 100644
--- a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ComputationalConfigure.java
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/core/response/handlers/ComputationalConfigure.java
@@ -30,6 +30,7 @@
 import com.epam.datalab.backendapi.core.response.folderlistener.FolderListenerExecutor;
 import com.epam.datalab.cloud.CloudProvider;
 import com.epam.datalab.dto.aws.computational.SparkComputationalCreateAws;
+import com.epam.datalab.dto.azure.computational.SparkComputationalCreateAzure;
 import com.epam.datalab.dto.base.DataEngineType;
 import com.epam.datalab.dto.base.computational.ComputationalBase;
 import com.epam.datalab.dto.gcp.computational.SparkComputationalCreateGcp;
@@ -66,7 +67,12 @@
                     return runConfigure(uuid, dto, DataEngineType.CLOUD_SERVICE);
                 }
             case AZURE:
-                return runConfigure(uuid, dto, DataEngineType.SPARK_STANDALONE);
+                if (dto instanceof SparkComputationalCreateAzure) {
+                    return runConfigure(uuid, dto, DataEngineType.SPARK_STANDALONE);
+                } else {
+                    return runConfigure(uuid, dto, DataEngineType.CLOUD_SERVICE);
+                }
+
             case GCP:
                 if (dto instanceof SparkComputationalCreateGcp) {
                     return runConfigure(uuid, dto, DataEngineType.SPARK_STANDALONE);
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/ImageResource.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/ImageResource.java
index b565556..d6484bd 100644
--- a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/ImageResource.java
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/ImageResource.java
@@ -59,6 +59,18 @@
         return Response.accepted(uuid).build();
     }
 
+    @POST
+    @Path("/terminate")
+    public Response terminateImage(@Auth UserInfo ui, ExploratoryImageDTO image) throws JsonProcessingException{
+        final String uuid = DockerCommands.generateUUID();
+
+        folderListenerExecutor.start(configuration.getImagesDirectory(), configuration.getResourceStatusPollTimeout(),
+                new ImageCreateCallbackHandler(selfService, uuid, DockerAction.TERMINATE_IMAGE, image));
+        String command = commandBuilder.buildCommand(getDockerCommand(DockerAction.TERMINATE_IMAGE, uuid, image), image);
+        commandExecutor.executeAsync(ui.getName(), uuid, command);
+        log.debug("Docker command: " + command);
+        return Response.accepted(uuid).build();
+    }
 
     @Override
     public String getResourceType() {
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/azure/ComputationalResourceAzure.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/azure/ComputationalResourceAzure.java
index effed2d..fc65179 100644
--- a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/azure/ComputationalResourceAzure.java
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/resources/azure/ComputationalResourceAzure.java
@@ -20,13 +20,27 @@
 package com.epam.datalab.backendapi.resources.azure;
 
 import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.core.Directories;
+import com.epam.datalab.backendapi.core.FileHandlerCallback;
+import com.epam.datalab.backendapi.core.commands.DockerAction;
+import com.epam.datalab.backendapi.core.commands.DockerCommands;
+import com.epam.datalab.backendapi.core.commands.RunDockerCommand;
+import com.epam.datalab.backendapi.core.response.handlers.ComputationalCallbackHandler;
+import com.epam.datalab.backendapi.core.response.handlers.ComputationalConfigure;
+import com.epam.datalab.backendapi.service.impl.DockerService;
 import com.epam.datalab.backendapi.service.impl.SparkClusterService;
+import com.epam.datalab.dto.azure.computational.AzureComputationalTerminateDTO;
+import com.epam.datalab.dto.azure.computational.ComputationalCreateAzure;
 import com.epam.datalab.dto.azure.computational.SparkComputationalCreateAzure;
+import com.epam.datalab.dto.base.DataEngineType;
+import com.epam.datalab.dto.base.computational.ComputationalBase;
 import com.epam.datalab.dto.computational.ComputationalClusterConfigDTO;
 import com.epam.datalab.dto.computational.ComputationalStartDTO;
 import com.epam.datalab.dto.computational.ComputationalStopDTO;
 import com.epam.datalab.dto.computational.ComputationalTerminateDTO;
+import com.epam.datalab.exceptions.DatalabException;
 import com.epam.datalab.rest.contracts.ComputationalAPI;
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.google.inject.Inject;
 import io.dropwizard.auth.Auth;
 import lombok.extern.slf4j.Slf4j;
@@ -37,16 +51,94 @@
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 
+import static com.epam.datalab.backendapi.core.commands.DockerAction.CREATE;
+import static com.epam.datalab.backendapi.core.commands.DockerAction.TERMINATE;
+
 @Path("/")
 @Consumes(MediaType.APPLICATION_JSON)
 @Produces(MediaType.APPLICATION_JSON)
 @Slf4j
-public class ComputationalResourceAzure implements ComputationalAPI {
+public class ComputationalResourceAzure extends DockerService implements DockerCommands {
+
+    @Inject
+    private ComputationalConfigure computationalConfigure;
 
     @Inject
     private SparkClusterService sparkClusterService;
 
     @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_CREATE_CLOUD_SPECIFIC)
+    public String create(@Auth UserInfo ui, ComputationalCreateAzure dto) {
+        log.debug("Create computational resources {} for user {}: {}", dto.getComputationalName(), ui.getName(), dto);
+        String uuid = DockerCommands.generateUUID();
+        folderListenerExecutor.start(configuration.getImagesDirectory(),
+                configuration.getResourceStatusPollTimeout(),
+                getFileHandlerCallback(CREATE, uuid, dto));
+        try {
+            commandExecutor.executeAsync(
+                    ui.getName(),
+                    uuid,
+                    commandBuilder.buildCommand(
+                            new RunDockerCommand()
+                                    .withInteractive()
+                                    .withName(nameContainer(dto.getEdgeUserName(), CREATE,
+                                            dto.getExploratoryName(), dto.getComputationalName()))
+                                    .withVolumeForRootKeys(configuration.getKeyDirectory())
+                                    .withVolumeForResponse(configuration.getImagesDirectory())
+                                    .withVolumeForLog(configuration.getDockerLogDirectory(),
+                                            DataEngineType.CLOUD_SERVICE.getName())
+                                    .withResource(DataEngineType.CLOUD_SERVICE.getName())
+                                    .withRequestId(uuid)
+                                    .withConfKeyName(configuration.getAdminKey())
+                                    .withActionCreate(DataEngineType.getDockerImageName(DataEngineType.CLOUD_SERVICE)),
+                            dto
+                    )
+            );
+        } catch (Exception t) {
+            throw new DatalabException("Could not create computational resource cluster", t);
+        }
+        return uuid;
+    }
+
+    @POST
+    @Path(ComputationalAPI.COMPUTATIONAL_TERMINATE_CLOUD_SPECIFIC)
+    public String terminate(@Auth UserInfo ui, AzureComputationalTerminateDTO dto) {
+
+        log.debug("Terminate computational resources {} for user {}: {}", dto.getComputationalName(), ui.getName(),
+                dto);
+        String uuid = DockerCommands.generateUUID();
+        folderListenerExecutor.start(configuration.getImagesDirectory(),
+                configuration.getResourceStatusPollTimeout(),
+                getFileHandlerCallback(TERMINATE, uuid, dto));
+        try {
+            commandExecutor.executeAsync(
+                    ui.getName(),
+                    uuid,
+                    commandBuilder.buildCommand(
+                            new RunDockerCommand()
+                                    .withInteractive()
+                                    .withName(nameContainer(dto.getEdgeUserName(), TERMINATE,
+                                            dto.getExploratoryName(), dto.getComputationalName()))
+                                    .withVolumeForRootKeys(configuration.getKeyDirectory())
+                                    .withVolumeForResponse(configuration.getImagesDirectory())
+                                    .withVolumeForLog(configuration.getDockerLogDirectory(), DataEngineType
+                                            .CLOUD_SERVICE.getName())
+                                    .withResource(DataEngineType.CLOUD_SERVICE.getName())
+                                    .withRequestId(uuid)
+                                    .withConfKeyName(configuration.getAdminKey())
+                                    .withActionTerminate(DataEngineType.getDockerImageName(DataEngineType
+                                            .CLOUD_SERVICE)),
+                            dto
+                    )
+            );
+        } catch (JsonProcessingException t) {
+            throw new DatalabException("Could not terminate computational resources cluster", t);
+        }
+
+        return uuid;
+    }
+
+    @POST
     @Path(ComputationalAPI.COMPUTATIONAL_CREATE_SPARK)
     public String create(@Auth UserInfo ui, SparkComputationalCreateAzure dto) {
         log.debug("Create computational Spark resources {} for user {}: {}",
@@ -91,4 +183,17 @@
         return sparkClusterService.updateConfig(ui, config);
     }
 
+    private FileHandlerCallback getFileHandlerCallback(DockerAction action, String uuid, ComputationalBase<?> dto){
+        return new ComputationalCallbackHandler(computationalConfigure, selfService, action, uuid, dto);
+    }
+
+    private String nameContainer(String user, DockerAction action, String exploratoryName, String name) {
+        return nameContainer(user, action.toString(), "computational", exploratoryName, name);
+    }
+
+    @Override
+    public String getResourceType() {
+        return Directories.DATA_ENGINE_SERVICE_LOG_DIRECTORY;
+    }
+
 }
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/ProjectServiceImpl.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/ProjectServiceImpl.java
index f92e1f4..0089169 100644
--- a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/ProjectServiceImpl.java
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/ProjectServiceImpl.java
@@ -35,6 +35,7 @@
 import com.epam.datalab.rest.client.RESTService;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.google.inject.Inject;
+import io.dropwizard.util.Duration;
 import lombok.extern.slf4j.Slf4j;
 
 import java.util.Objects;
@@ -96,9 +97,13 @@
     private String executeDocker(UserInfo userInfo, ResourceBaseDTO dto, DockerAction action, String projectName,
                                  String resourceType, String image, String endpoint) {
         String uuid = DockerCommands.generateUUID();
+        Duration timeout = configuration.getKeyLoaderPollTimeout();
+        if(action == DockerAction.CREATE){
+            timeout = Duration.minutes(timeout.toMinutes() + 30);
+        }
 
         folderListenerExecutor.start(configuration.getKeyLoaderDirectory(),
-                configuration.getKeyLoaderPollTimeout(),
+                timeout,
                 new ProjectCallbackHandler(selfService, userInfo.getName(), uuid,
                         action, CALLBACK_URI, projectName, getEdgeClass(), endpoint));
 
diff --git a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/azure/BucketServiceAzureImpl.java b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/azure/BucketServiceAzureImpl.java
index 0db7f0c..4c56b2c 100644
--- a/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/azure/BucketServiceAzureImpl.java
+++ b/services/provisioning-service/src/main/java/com/epam/datalab/backendapi/service/impl/azure/BucketServiceAzureImpl.java
@@ -129,7 +129,7 @@
                 .bucket(bucket)
                 .object(blob.getName())
                 .size(String.valueOf(blob.getProperties().getContentLength()))
-                .lastModifiedDate(blob.getProperties().getLastModified().toEpochSecond())
+                .lastModifiedDate(blob.getProperties().getLastModified().toEpochSecond()*1000)
                 .build();
     }
 
diff --git a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_create_image.json b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_create_image.json
index 3538ddf..bc2c789 100644
--- a/services/provisioning-service/src/main/resources/mock_response/aws/notebook_create_image.json
+++ b/services/provisioning-service/src/main/resources/mock_response/aws/notebook_create_image.json
@@ -7,7 +7,7 @@
          "user_name": "${EDGE_USER_NAME}",
          "application": "${APPLICATION}",
          "image_id": "${IMAGE_NAME}-${REQUEST_ID}",
-         "status" : "created",
+         "status" : "active",
          "Action": "Create image from notebook"
       },
       "log": "/var/log/datalab/notebook/notebook_${EDGE_USER_NAME}_${REQUEST_ID}.log"
diff --git a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_create_image.json b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_create_image.json
index b34972d..c0eda41 100644
--- a/services/provisioning-service/src/main/resources/mock_response/azure/notebook_create_image.json
+++ b/services/provisioning-service/src/main/resources/mock_response/azure/notebook_create_image.json
@@ -7,7 +7,7 @@
          "user_name": "${EDGE_USER_NAME}",
          "application": "${APPLICATION}",
          "image_id": "${IMAGE_NAME}-${REQUEST_ID}",
-         "status" : "created",
+         "status" : "active",
          "ip" : "102.011.10.3",
          "Action": "Create image from notebook"
       },
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_create_image.json b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_create_image.json
index d1a5d34..e381a9a 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_create_image.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_create_image.json
@@ -7,7 +7,7 @@
          "user_name": "${EDGE_USER_NAME}",
          "application": "${APPLICATION}",
          "image_id": "${IMAGE_NAME}-${REQUEST_ID}",
-         "status": "created",
+         "status": "active",
          "ip": "102.011.10.3",
          "Action": "Create image from notebook"
       },
diff --git a/services/self-service/pom.xml b/services/self-service/pom.xml
index a3eba43..540932f 100644
--- a/services/self-service/pom.xml
+++ b/services/self-service/pom.xml
@@ -190,7 +190,7 @@
         <dependency>
             <groupId>commons-io</groupId>
             <artifactId>commons-io</artifactId>
-            <version>2.6</version>
+            <version>2.7</version>
         </dependency>
         <dependency>
             <groupId>org.apache.commons</groupId>
diff --git a/services/self-service/self-service.yml b/services/self-service/self-service.yml
index 9e20bf0..4970a6b 100644
--- a/services/self-service/self-service.yml
+++ b/services/self-service/self-service.yml
@@ -28,6 +28,11 @@
 minEmrSpotInstanceBidPct: 20
 maxEmrSpotInstanceBidPct: 90
 
+# Minimum and maximum number of slave HDInsight instances that could be created
+minHDInsightInstanceCount: 3
+maxHDInsightInstanceCount: 29
+
+
 # Maximum length for gcp user name (due to gcp restrictions)
 maxUserNameLength: 10
 # Minimum and maximum number of slave Dataproc instances that could be created
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/SelfServiceApplication.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/SelfServiceApplication.java
index 08ebf1a..027ce4f 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/SelfServiceApplication.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/SelfServiceApplication.java
@@ -27,26 +27,7 @@
 import com.epam.datalab.backendapi.dropwizard.listeners.RestoreHandlerStartupListener;
 import com.epam.datalab.backendapi.healthcheck.MongoHealthCheck;
 import com.epam.datalab.backendapi.modules.ModuleFactory;
-import com.epam.datalab.backendapi.resources.ApplicationSettingResource;
-import com.epam.datalab.backendapi.resources.AuditResource;
-import com.epam.datalab.backendapi.resources.BackupResource;
-import com.epam.datalab.backendapi.resources.EndpointResource;
-import com.epam.datalab.backendapi.resources.EnvironmentResource;
-import com.epam.datalab.backendapi.resources.ExploratoryResource;
-import com.epam.datalab.backendapi.resources.GitCredsResource;
-import com.epam.datalab.backendapi.resources.ImageExploratoryResource;
-import com.epam.datalab.backendapi.resources.InfrastructureInfoResource;
-import com.epam.datalab.backendapi.resources.InfrastructureTemplateResource;
-import com.epam.datalab.backendapi.resources.KeycloakResource;
-import com.epam.datalab.backendapi.resources.LibExploratoryResource;
-import com.epam.datalab.backendapi.resources.OdahuResource;
-import com.epam.datalab.backendapi.resources.ProjectResource;
-import com.epam.datalab.backendapi.resources.SchedulerJobResource;
-import com.epam.datalab.backendapi.resources.SystemInfoResource;
-import com.epam.datalab.backendapi.resources.UserGroupResource;
-import com.epam.datalab.backendapi.resources.UserRoleResource;
-import com.epam.datalab.backendapi.resources.UserSettingsResource;
-import com.epam.datalab.backendapi.resources.ChangePropertiesResource;
+import com.epam.datalab.backendapi.resources.*;
 import com.epam.datalab.backendapi.resources.callback.BackupCallback;
 import com.epam.datalab.backendapi.resources.callback.CheckInactivityCallback;
 import com.epam.datalab.backendapi.resources.callback.ComputationalCallback;
@@ -200,6 +181,7 @@
 	    jersey.register(injector.getInstance(OdahuResource.class));
 	    jersey.register(injector.getInstance(OdahuCallback.class));
 	    jersey.register(injector.getInstance(ChangePropertiesResource.class));
+	    jersey.register(injector.getInstance(ConnectedPlatformResource.class));
     }
 
     private void disableGzipHandlerForGuacamoleServlet(Server server) {
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/conf/SelfServiceApplicationConfiguration.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/conf/SelfServiceApplicationConfiguration.java
index 66ccb72..6488c2c 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/conf/SelfServiceApplicationConfiguration.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/conf/SelfServiceApplicationConfiguration.java
@@ -55,6 +55,15 @@
     @JsonProperty
     private int maxEmrSpotInstanceBidPct;
 
+
+    @Min(value = 2)
+    @JsonProperty
+    private int minHDInsightInstanceCount;
+
+    @Max(value = 1000)
+    @JsonProperty
+    private int maxHDInsightInstanceCount;
+
     @Min(value = 2)
     @JsonProperty
     private int minSparkInstanceCount;
@@ -180,6 +189,14 @@
         return maxEmrSpotInstanceBidPct;
     }
 
+    public int getMinHDInsightInstanceCount() {
+        return minHDInsightInstanceCount;
+    }
+
+    public int getMaxHDInsightInstanceCount() {
+        return maxHDInsightInstanceCount;
+    }
+
     public int getMinSparkInstanceCount() {
         return minSparkInstanceCount;
     }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/AuditDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/AuditDAO.java
index ae840fb..5e78f12 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/AuditDAO.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/AuditDAO.java
@@ -21,6 +21,8 @@
 
 import com.epam.datalab.backendapi.domain.AuditDTO;
 import com.epam.datalab.backendapi.domain.AuditPaginationDTO;
+import com.epam.datalab.backendapi.domain.AuditReportLine;
+import com.epam.datalab.backendapi.resources.dto.AuditFilter;
 
 import java.util.List;
 
@@ -28,4 +30,6 @@
     void save(AuditDTO audit);
 
     List<AuditPaginationDTO> getAudit(List<String> users, List<String> projects, List<String> resourceNames, List<String> resourceTypes, String dateStart, String dateEnd, int pageNumber, int pageSize);
+
+    List<AuditReportLine> aggregateAuditReport(AuditFilter auditFilter);
 }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/AuditDAOImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/AuditDAOImpl.java
index 34c14a2..9d0d0fd 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/AuditDAOImpl.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/AuditDAOImpl.java
@@ -21,6 +21,8 @@
 
 import com.epam.datalab.backendapi.domain.AuditDTO;
 import com.epam.datalab.backendapi.domain.AuditPaginationDTO;
+import com.epam.datalab.backendapi.domain.AuditReportLine;
+import com.epam.datalab.backendapi.resources.dto.AuditFilter;
 import com.epam.datalab.exceptions.DatalabException;
 import com.mongodb.client.model.Facet;
 import com.mongodb.client.model.Filters;
@@ -33,6 +35,7 @@
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
 import java.time.Instant;
+import java.time.ZoneId;
 import java.time.ZoneOffset;
 import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
@@ -69,6 +72,8 @@
     private static final String USER_FACET = "userFacet";
     private static final String PROJECT_FACET = "projectFacet";
     private static final String RESOURCE_TYPE_FACET = "typeFacet";
+    private static final String DATALAB_ID = "datalabId";
+    private static final String ACTION = "action";
 
     @Override
     public void save(AuditDTO audit) {
@@ -78,6 +83,25 @@
     @Override
     public List<AuditPaginationDTO> getAudit(List<String> users, List<String> projects, List<String> resourceNames, List<String> resourceTypes, String dateStart, String dateEnd,
                                              int pageNumber, int pageSize) {
+        List<Bson> facets = getFacets(users, projects, resourceNames, resourceTypes, dateStart, dateEnd, pageNumber, pageSize);
+        return StreamSupport.stream(aggregate(AUDIT_COLLECTION, facets).spliterator(), false)
+                .map(this::toAuditPaginationDTO)
+                .collect(Collectors.toList());
+    }
+
+    public List<AuditReportLine> aggregateAuditReport(AuditFilter filter) {
+        List<Bson> facets = getFacets(filter.getUsers(), filter.getProjects(), filter.getResourceNames(), filter.getResourceTypes(), filter.getDateStart(), filter.getDateEnd(), filter.getPageNumber(), filter.getPageSize());
+        List<Document> auditDocuments  = new ArrayList<>();
+        StreamSupport.stream(aggregate(AUDIT_COLLECTION, facets).spliterator(), false)
+                .map(document -> (ArrayList<Document>)document.get(AUDIT_FACET))
+                .forEach(auditDocuments::addAll);
+        return auditDocuments.stream()
+                .map(this::toAuditReport)
+                .collect(Collectors.toList());
+    }
+
+    private List<Bson> getFacets(List<String> users, List<String> projects, List<String> resourceNames, List<String> resourceTypes, String dateStart, String dateEnd,
+                                 int pageNumber, int pageSize){
         List<Bson> valuesPipeline = new ArrayList<>();
         List<Bson> countPipeline = new ArrayList<>();
         List<Bson> matchCriteria = matchCriteria(users, projects, resourceNames, resourceTypes, dateStart, dateEnd);
@@ -95,12 +119,9 @@
         List<Bson> resourceNameFilter = Collections.singletonList(group(getGroupingFields(RESOURCE_NAME_FIELD)));
         List<Bson> resourceTypeFilter = Collections.singletonList(group(getGroupingFields(RESOURCE_TYPE_FIELD)));
 
-        List<Bson> facets = Collections.singletonList(facet(new Facet(AUDIT_FACET, valuesPipeline), new Facet(TOTAL_COUNT_FACET, countPipeline),
+        return Collections.singletonList(facet(new Facet(AUDIT_FACET, valuesPipeline), new Facet(TOTAL_COUNT_FACET, countPipeline),
                 new Facet(RESOURCE_NAME_FACET, resourceNameFilter), new Facet(USER_FACET, userFilter), new Facet(PROJECT_FACET, projectFilter),
                 new Facet(RESOURCE_TYPE_FACET, resourceTypeFilter)));
-        return StreamSupport.stream(aggregate(AUDIT_COLLECTION, facets).spliterator(), false)
-                .map(this::toAuditPaginationDTO)
-                .collect(Collectors.toList());
     }
 
     private List<Bson> matchCriteria(List<String> users, List<String> projects, List<String> resourceNames, List<String> resourceTypes, String dateStart, String dateEnd) {
@@ -144,6 +165,18 @@
                 .build();
     }
 
+    private AuditReportLine toAuditReport(Document doc) {
+        return AuditReportLine.builder()
+                .datalabId(doc.getString(DATALAB_ID))
+                .project(doc.getString(PROJECT))
+                .resourceName(doc.getString(RESOURCE_NAME_FIELD))
+                .action(doc.getString(ACTION))
+                .user(doc.getString(USER))
+                .resourceType(doc.getString(RESOURCE_TYPE_FIELD))
+                .timestamp(doc.getDate(TIMESTAMP_FIELD).toInstant().atZone(ZoneId.systemDefault()).toLocalDate())
+                .build();
+    }
+
     private Set<String> getFilter(Document document, String facet, String field) {
         return ((List<Document>) document.get(facet))
                 .stream()
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ConnectedPlatformsDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ConnectedPlatformsDAO.java
new file mode 100644
index 0000000..a48b808
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ConnectedPlatformsDAO.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.dao;
+
+import com.epam.datalab.backendapi.resources.dto.ConnectedPlatformDTO;
+
+import java.util.List;
+
+public interface ConnectedPlatformsDAO {
+
+    boolean exist(String name);
+    void addPlatform(ConnectedPlatformDTO connectedPlatformDTO);
+
+    List<ConnectedPlatformDTO> getAll();
+
+    List<ConnectedPlatformDTO> getUserPlatforms(String userName);
+
+    void delete(String user, String name);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ConnectedPlatformsDAOImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ConnectedPlatformsDAOImpl.java
new file mode 100644
index 0000000..04383a7
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ConnectedPlatformsDAOImpl.java
@@ -0,0 +1,59 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.dao;
+
+import com.epam.datalab.backendapi.resources.dto.ConnectedPlatformDTO;
+
+import java.util.List;
+
+import static com.mongodb.client.model.Filters.and;
+import static com.mongodb.client.model.Filters.eq;
+
+public class ConnectedPlatformsDAOImpl extends BaseDAO implements ConnectedPlatformsDAO {
+
+    private static final String CONNECTED_PLATFORMS = "connectedPlatforms";
+    private static final String NAME = "name";
+    private static final String USER = "user";
+
+    @Override
+    public boolean exist(String name) {
+        return findOne(CONNECTED_PLATFORMS, eq(NAME, name)).isPresent();
+    }
+
+    @Override
+    public void addPlatform(ConnectedPlatformDTO connectedPlatformDTO) {
+        insertOne(CONNECTED_PLATFORMS, connectedPlatformDTO);
+    }
+
+    @Override
+    public List<ConnectedPlatformDTO> getAll() {
+        return find(CONNECTED_PLATFORMS, ConnectedPlatformDTO.class);
+    }
+
+    @Override
+    public List<ConnectedPlatformDTO> getUserPlatforms(String userName) {
+        return find(CONNECTED_PLATFORMS, eq(USER, userName), ConnectedPlatformDTO.class);
+    }
+
+    @Override
+    public void delete(String user, String name) {
+        deleteOne(CONNECTED_PLATFORMS, and(eq(USER,user),eq(NAME,name)));
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAO.java
index d8e8987..946b2fb 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAO.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAO.java
@@ -20,6 +20,7 @@
 package com.epam.datalab.backendapi.dao;
 
 import com.epam.datalab.backendapi.resources.dto.ImageInfoRecord;
+import com.epam.datalab.dto.SharedWith;
 import com.epam.datalab.dto.exploratory.ImageStatus;
 import com.epam.datalab.dto.exploratory.LibStatus;
 import com.epam.datalab.model.exploratory.Image;
@@ -36,11 +37,23 @@
 
     void updateImageFields(Image image);
 
+    void updateImageStatus(String user, String imageName, String project, String endpoint, ImageStatus status);
+    void updateImageStatus(String imageName, String projectName, String endpoint, ImageStatus status);
+
     List<ImageInfoRecord> getImages(String user, String dockerImage, String project, String endpoint, ImageStatus... statuses);
 
+    List<ImageInfoRecord> getImages(String project, String endpoint, String dockerImage);
+
+    List<ImageInfoRecord> getImagesOfUser(String user);
+
     List<ImageInfoRecord> getImagesForProject(String project);
 
+    List<ImageInfoRecord> getAllImages();
     Optional<ImageInfoRecord> getImage(String user, String name, String project, String endpoint);
 
-    List<Library> getLibraries(String user, String imageFullName, String project, String endpoint, LibStatus status);
+    Optional<ImageInfoRecord> getImage(String name, String project, String endpoint);
+
+    List<Library> getLibraries(String imageName,  String project, String endpoint, LibStatus status);
+
+    void updateSharing(SharedWith sharedWith, String imageName, String project, String endpoint);
 }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAOImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAOImpl.java
index 234a15e..12c0ec6 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAOImpl.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/ImageExploratoryDAOImpl.java
@@ -20,6 +20,7 @@
 package com.epam.datalab.backendapi.dao;
 
 import com.epam.datalab.backendapi.resources.dto.ImageInfoRecord;
+import com.epam.datalab.dto.SharedWith;
 import com.epam.datalab.dto.exploratory.ImageStatus;
 import com.epam.datalab.dto.exploratory.LibStatus;
 import com.epam.datalab.model.exploratory.Image;
@@ -42,6 +43,7 @@
 import static com.mongodb.client.model.Projections.excludeId;
 import static com.mongodb.client.model.Projections.fields;
 import static com.mongodb.client.model.Projections.include;
+import static com.mongodb.client.model.Updates.set;
 
 @Singleton
 public class ImageExploratoryDAOImpl extends BaseDAO implements ImageExploratoryDAO {
@@ -55,6 +57,8 @@
     private static final String PROJECT = "project";
     private static final String ENDPOINT = "endpoint";
 
+    private static final String SHARED_WITH = "sharedWith";
+
     @Override
     public boolean exist(String image, String project) {
         return findOne(MongoCollections.IMAGES, imageProjectCondition(image, project)).isPresent();
@@ -73,6 +77,16 @@
     }
 
     @Override
+    public void updateImageStatus(String user, String imageName, String project, String endpoint, ImageStatus status) {
+        final Bson condition = userImageCondition(user, imageName, project, endpoint);
+        updateOne(MongoCollections.IMAGES, condition, set(STATUS,status.toString()));
+    }
+    @Override
+    public void updateImageStatus(String imageName, String projectName, String endpoint, ImageStatus status) {
+        updateOne(MongoCollections.IMAGES, and(eq(IMAGE_NAME, imageName), eq(PROJECT, projectName), eq(ENDPOINT, endpoint)), set(STATUS,status.toString()));
+    }
+
+    @Override
     public List<ImageInfoRecord> getImages(String user, String dockerImage, String project, String endpoint, ImageStatus... statuses) {
         return find(MongoCollections.IMAGES,
                 userImagesCondition(user, dockerImage, project, endpoint, statuses),
@@ -80,6 +94,21 @@
     }
 
     @Override
+    public List<ImageInfoRecord> getImages(String project, String endpoint, String dockerImage) {
+        return find(MongoCollections.IMAGES,
+                imageProjectEndpointDockerCondition(project, endpoint, dockerImage),
+                ImageInfoRecord.class);
+    }
+
+
+    @Override
+    public List<ImageInfoRecord> getImagesOfUser(String user) {
+        return find(MongoCollections.IMAGES,
+                eq(USER, user),
+                ImageInfoRecord.class);
+    }
+
+    @Override
     public List<ImageInfoRecord> getImagesForProject(String project) {
         return find(MongoCollections.IMAGES,
                 eq(PROJECT, project),
@@ -87,24 +116,38 @@
     }
 
     @Override
+    public List<ImageInfoRecord> getAllImages() {
+        return find(MongoCollections.IMAGES, ImageInfoRecord.class);
+    }
+
+    @Override
     public Optional<ImageInfoRecord> getImage(String user, String name, String project, String endpoint) {
         return findOne(MongoCollections.IMAGES, userImageCondition(user, name, project, endpoint), ImageInfoRecord.class);
     }
 
     @Override
-    @SuppressWarnings("unchecked")
-    public List<Library> getLibraries(String user, String imageFullName, String project, String endpoint, LibStatus status) {
-        return ((List<Document>) libDocument(user, imageFullName, project, endpoint, status)
+    public Optional<ImageInfoRecord> getImage(String name, String project, String endpoint) {
+        return findOne(MongoCollections.IMAGES, imageProjectEndpointCondition(name, project, endpoint), ImageInfoRecord.class);
+    }
+
+    @Override
+    public List<Library> getLibraries(String imageName,  String project, String endpoint, LibStatus status) {
+        return ((List<Document>) libDocument(imageName, project, endpoint, status)
                 .orElse(emptyLibrariesDocument()).get(LIBRARIES))
                 .stream()
                 .map(d -> convertFromDocument(d, Library.class))
                 .collect(Collectors.toList());
     }
 
-    private Optional<Document> libDocument(String user, String imageFullName, String project, String endpoint,
+    @Override
+    public void updateSharing(SharedWith sharedWith, String imageName, String project, String endpoint) {
+        updateOne(MongoCollections.IMAGES, and(eq(IMAGE_NAME,imageName),eq(PROJECT,project),eq(ENDPOINT,endpoint)), set(SHARED_WITH, convertToBson(sharedWith)));
+    }
+
+    private Optional<Document> libDocument(String imageName, String project, String endpoint,
                                            LibStatus status) {
         return findOne(MongoCollections.IMAGES,
-                imageLibraryCondition(user, imageFullName, project, endpoint, status),
+                imageLibraryCondition(imageName,project,endpoint,status),
                 fields(include(LIBRARIES), excludeId()));
     }
 
@@ -112,9 +155,8 @@
         return new Document(LIBRARIES, Collections.emptyList());
     }
 
-    private Bson imageLibraryCondition(String user, String imageFullName, String project, String endpoint,
-                                       LibStatus status) {
-        return and(eq(USER, user), eq(IMAGE_NAME, imageFullName), eq(PROJECT, project), eq(ENDPOINT, endpoint),
+    private Bson imageLibraryCondition(String imageName, String project, String endpoint, LibStatus status){
+        return and(eq(IMAGE_NAME, imageName), eq(PROJECT, project), eq(ENDPOINT, endpoint),
                 elemMatch(LIBRARIES, eq(STATUS, status.name())));
     }
 
@@ -146,6 +188,18 @@
         return and(eq(IMAGE_NAME, image), eq(PROJECT, project));
     }
 
+    private Bson imageProjectEndpointCondition(String image, String project, String endpoint) {
+        return and(eq(IMAGE_NAME, image), eq(PROJECT, project), eq(ENDPOINT, endpoint));
+    }
+
+    private Bson imageUserProjectCondition(String user, String project) {
+        return and(eq(USER, user), eq(PROJECT, project));
+    }
+
+    private Bson imageProjectEndpointDockerCondition(String project, String endpoint, String dockerImage){
+        return and(eq(PROJECT, project), eq(ENDPOINT, endpoint), eq(DOCKER_IMAGE,dockerImage));
+    }
+
     private Document getUpdatedFields(Image image) {
         return new Document(STATUS, image.getStatus().toString())
                 .append(IMAGE_FULL_NAME, image.getFullName())
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/SecurityDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/SecurityDAO.java
index 85e836e..2522036 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/SecurityDAO.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/SecurityDAO.java
@@ -39,10 +39,7 @@
 import java.util.stream.Collectors;
 
 import static com.epam.datalab.backendapi.dao.MongoCollections.ROLES;
-import static com.mongodb.client.model.Filters.and;
-import static com.mongodb.client.model.Filters.eq;
-import static com.mongodb.client.model.Filters.gte;
-import static com.mongodb.client.model.Filters.ne;
+import static com.mongodb.client.model.Filters.*;
 import static com.mongodb.client.model.Projections.exclude;
 import static com.mongodb.client.model.Projections.fields;
 import static com.mongodb.client.model.Projections.include;
@@ -109,6 +106,12 @@
                 .map(d -> convertFromDocument((Document) d.get(TOKEN_RESPONSE), AccessTokenResponse.class));
     }
 
+    public Set<String> getUserNames(String name){
+        return stream(find(SECURITY_COLLECTION, regex(ID, name,"i")))
+                .map(document -> document.getString(ID))
+                .collect(Collectors.toSet());
+    }
+
     @SuppressWarnings("unchecked")
     private Set<String> toUsers(Document d) {
         final Object users = d.get("users");
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserGroupDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserGroupDAO.java
index 1411bf9..75df7d2 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserGroupDAO.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserGroupDAO.java
@@ -30,4 +30,6 @@
     Set<String> getUserGroups(String user);
 
     Set<String> getUsers(String group);
+
+    Set<String> getGroupNames(String name);
 }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserGroupDAOImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserGroupDAOImpl.java
index 4fa0488..26eaae8 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserGroupDAOImpl.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserGroupDAOImpl.java
@@ -28,8 +28,7 @@
 import java.util.stream.Collectors;
 
 import static com.epam.datalab.backendapi.dao.MongoCollections.USER_GROUPS;
-import static com.mongodb.client.model.Filters.elemMatch;
-import static com.mongodb.client.model.Filters.eq;
+import static com.mongodb.client.model.Filters.*;
 
 @Singleton
 public class UserGroupDAOImpl extends BaseDAO implements UserGroupDAO {
@@ -65,4 +64,11 @@
                 .map(document -> (List<String>) document.get(USERS_FIELD))
                 .orElseThrow(() -> new DatalabException(String.format("Group %s not found", group))));
     }
+
+    @Override
+    public Set<String> getGroupNames(String name) {
+        return stream(find(USER_GROUPS, regex(ID, name,"i")))
+                .map(document -> document.getString(ID))
+                .collect(Collectors.toSet());
+    }
 }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserRoleDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserRoleDAO.java
index 89bc126..07a4af4 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserRoleDAO.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserRoleDAO.java
@@ -29,6 +29,8 @@
 public interface UserRoleDAO {
     List<UserRoleDTO> findAll();
 
+    UserRoleDTO findById(String roleId);
+
     void insert(UserRoleDTO dto);
 
     void insert(List<UserRoleDTO> roles);
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserRoleDAOImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserRoleDAOImpl.java
index 1081dee..63c221f 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserRoleDAOImpl.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserRoleDAOImpl.java
@@ -80,6 +80,11 @@
     }
 
     @Override
+    public UserRoleDTO findById(String roleId) {
+        return findOne(MongoCollections.ROLES, in(ID, roleId),UserRoleDTO.class).orElse(null);
+    }
+
+    @Override
     public void insert(UserRoleDTO dto) {
         insertOne(MongoCollections.ROLES, dto, dto.getId());
     }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserSettingsDAO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserSettingsDAO.java
index 7e06eb3..dad4c0f 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserSettingsDAO.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/dao/UserSettingsDAO.java
@@ -20,14 +20,20 @@
 package com.epam.datalab.backendapi.dao;
 
 import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.ImageFilter;
 import com.epam.datalab.backendapi.resources.dto.UserDTO;
 import io.dropwizard.auth.Auth;
 import org.apache.commons.lang3.StringUtils;
+import org.bson.Document;
+
 
 import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 import static com.epam.datalab.backendapi.dao.MongoCollections.USER_SETTINGS;
-import static com.mongodb.client.model.Filters.eq;
+import static com.mongodb.client.model.Filters.*;
+import static com.mongodb.client.model.Projections.*;
 import static com.mongodb.client.model.Updates.set;
 
 /**
@@ -37,6 +43,8 @@
     private static final String USER_UI_SETTINGS_FIELD = "userUISettings";
     private static final String USER_ALLOWED_BUDGET = "allowedBudget";
 
+    private static final String USER_IMAGE_FILTER = "imageFilter";
+
     /**
      * Returns the user preferences of UI dashboard.
      *
@@ -74,4 +82,24 @@
                 .flatMap(d -> Optional.ofNullable(d.getInteger(USER_ALLOWED_BUDGET)));
     }
 
+    public Optional<ImageFilter> getImageFilter(String user){
+         return findOne(USER_SETTINGS, and(eq(ID, user), notNull(USER_IMAGE_FILTER)),
+                fields(include(USER_IMAGE_FILTER), excludeId()))
+                 .map(d -> convertFromDocument((Document) d.get(USER_IMAGE_FILTER), ImageFilter.class));
+    }
+
+
+    public void setUserImageFilter(String userName, ImageFilter imageFilter) {
+        updateOne(USER_SETTINGS,
+                eq(ID, userName),
+                set(USER_IMAGE_FILTER, convertToBson(imageFilter)),
+                true);
+    }
+
+    public Set<String> getUserNames(String name){
+        return stream(find(USER_SETTINGS, regex(ID, name,"i")))
+                .map(document -> document.getString(ID))
+                .collect(Collectors.toSet());
+    }
+
 }
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditActionEnum.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditActionEnum.java
index 65fdcda..f8ffea0 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditActionEnum.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditActionEnum.java
@@ -20,6 +20,6 @@
 package com.epam.datalab.backendapi.domain;
 
 public enum AuditActionEnum {
-	CREATE, RECREATE, SET_UP_SCHEDULER, START, STOP, TERMINATE, RECONFIGURE, UPDATE, CONNECT, DISCONNECT, UPLOAD,
+	CREATE, RECREATE, SET_UP_SCHEDULER, START, STOP, TERMINATE, RECONFIGURE, UPDATE, CONNECT, DISCONNECT, UPLOAD, UPDATE_SHARING,
 	DOWNLOAD, DELETE, INSTALL_LIBS, FOLLOW_LINK, LOG_IN
 }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditReport.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditReport.java
new file mode 100644
index 0000000..69663dc
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditReport.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.domain;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDate;
+import java.util.List;
+
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class AuditReport {
+    private String name;
+    @JsonProperty("report_lines")
+    private List<AuditReportLine> reportLines;
+    @JsonProperty("from")
+    private LocalDate usageDateFrom;
+    @JsonProperty("to")
+    private LocalDate usageDateTo;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditReportLine.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditReportLine.java
new file mode 100644
index 0000000..cb510a1
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditReportLine.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDate;
+
+@Data
+@Builder
+@JsonIgnoreProperties(ignoreUnknown = true)
+@AllArgsConstructor
+@NoArgsConstructor
+public class AuditReportLine {
+    private String datalabId;
+    private String action;
+    private String resourceType;
+    private String resourceName;
+    private String project;
+    private String user;
+    private LocalDate timestamp;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditResourceTypeEnum.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditResourceTypeEnum.java
index 1ca0fdf..6ac2ef5 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditResourceTypeEnum.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/AuditResourceTypeEnum.java
@@ -20,5 +20,5 @@
 package com.epam.datalab.backendapi.domain;
 
 public enum AuditResourceTypeEnum {
-    PROJECT, EDGE_NODE, NOTEBOOK, COMPUTE, BUCKET, ENDPOINT, GROUP, IMAGE, GIT_ACCOUNT, LOG_IN, WEB_TERMINAL
+    PROJECT, EDGE_NODE, INSTANCE, COMPUTE, BUCKET, ENDPOINT, GROUP, IMAGE, GIT_ACCOUNT, LOG_IN, WEB_TERMINAL
 }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/NotebookTemplate.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/NotebookTemplate.java
index 10eb99e..83908b8 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/NotebookTemplate.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/domain/NotebookTemplate.java
@@ -25,16 +25,18 @@
 @Getter
 @AllArgsConstructor
 public enum NotebookTemplate {
-    JUPYTER("Jupyter notebook 6.1.6"),
-    JUPYTER_LAB("JupyterLab 0.35.6"),
-    ZEPPELIN("Apache Zeppelin 0.9.0"),
+    JUPYTER("Jupyter 6.4.12"),
+    JUPYTER_GPU("Jupyter 6.4.12 with GPU"),
+    JUPYTER_LAB("JupyterLab 3.4.3"),
+    ZEPPELIN("Apache Zeppelin 0.9.1"),
     DEEP_LEARNING("Deep Learning  2.4"),
-    TENSOR("Jupyter with TensorFlow 2.3.2"),
-    TENSOR_RSTUDIO("RStudio with TensorFlow 2.3.2"),
-    RSTUDIO("RStudio 1.4.1103"),
+    TENSOR("Jupyter with TensorFlow 2.9.1"),
+    TENSOR_JUPYTERLAB("JupyterLab with TensorFlow 2.9.1"),
+    TENSOR_RSTUDIO("RStudio with TensorFlow 2.9.1"),
+    RSTUDIO("RStudio 2022.02.2-485"),
     TENSOR_GCP("Jupyter with TensorFlow 2.1.0"),
     DEEP_LEARNING_GCP("Deeplearning notebook"),
-    DEEP_LEARNING_AWS("Deep Learning AMI Version 42.1"),
+    DEEP_LEARNING_AWS("Deep Learning AMI Version 60.2"),
     DEEP_LEARNING_AZURE("Data Science Virtual Machine - Ubuntu 18.04");
 
 
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/DevModule.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/DevModule.java
index 6da6ee7..6915524 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/DevModule.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/DevModule.java
@@ -119,6 +119,8 @@
         bind(BillingDAO.class).to(BaseBillingDAO.class);
         bind(AuditDAO.class).to(AuditDAOImpl.class);
         bind(BucketService.class).to(BucketServiceImpl.class);
+        bind(ConnectedPlatformsService.class).to(ConnectedPlatformsServiceImpl.class);
+        bind(ConnectedPlatformsDAO.class).to(ConnectedPlatformsDAOImpl.class);
     }
 
     private void configureCors(Environment environment) {
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/ProductionModule.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/ProductionModule.java
index 15df056..6d8dc4c 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/ProductionModule.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/modules/ProductionModule.java
@@ -111,6 +111,8 @@
         bind(TagService.class).to(TagServiceImpl.class);
         bind(SecurityService.class).to(SecurityServiceImpl.class);
         bind(KeycloakService.class).to(KeycloakServiceImpl.class);
+        bind(ConnectedPlatformsService.class).to(ConnectedPlatformsServiceImpl.class);
+        bind(ConnectedPlatformsDAO.class).to(ConnectedPlatformsDAOImpl.class);
         bind(Client.class).toInstance(httpClient);
     }
 }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/AuditResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/AuditResource.java
index aa04fd0..8dade38 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/AuditResource.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/AuditResource.java
@@ -21,18 +21,23 @@
 
 import com.epam.datalab.auth.UserInfo;
 import com.epam.datalab.backendapi.domain.AuditCreateDTO;
+import com.epam.datalab.backendapi.resources.dto.AuditFilter;
+import com.epam.datalab.backendapi.resources.dto.BillingFilter;
+import com.epam.datalab.backendapi.resources.dto.ExportBillingFilter;
 import com.epam.datalab.backendapi.service.AuditService;
 import com.epam.datalab.model.StringList;
 import com.google.inject.Inject;
 import io.dropwizard.auth.Auth;
 
 import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
@@ -67,4 +72,20 @@
                 .ok(auditService.getAudit(users, projects, resourceNames, resourceTypes, dateStart, dateEnd, pageNumber, pageSize))
                 .build();
     }
+
+    @POST
+    @Path("/report")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getAuditReport(@Auth UserInfo userInfo, AuditFilter filter) {
+        return Response.ok(auditService.getAuditReport(filter)).build();
+    }
+
+    @POST
+    @Path("/report/download")
+    @Produces(MediaType.APPLICATION_OCTET_STREAM)
+    public Response downloadAuditReport(@Auth UserInfo userInfo, AuditFilter filter) {
+        return Response.ok(auditService.downloadAuditReport(filter))
+                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"audit-report.csv\"")
+                .build();
+    }
 }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ConnectedPlatformResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ConnectedPlatformResource.java
new file mode 100644
index 0000000..e664b8b
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ConnectedPlatformResource.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.resources;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.ConnectedPlatformAddFrom;
+import com.epam.datalab.backendapi.resources.dto.ConnectedPlatformType;
+import com.epam.datalab.backendapi.service.ConnectedPlatformsService;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.annotation.security.RolesAllowed;
+import javax.validation.Valid;
+import javax.ws.rs.*;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Path("connected_platforms")
+@Consumes(MediaType.APPLICATION_JSON)
+@Produces(MediaType.APPLICATION_JSON)
+@Slf4j
+public class ConnectedPlatformResource {
+
+    private final ConnectedPlatformsService connectedPlatformsService;
+
+    @Inject
+    public ConnectedPlatformResource(ConnectedPlatformsService connectedPlatformsService) {
+        this.connectedPlatformsService = connectedPlatformsService;
+    }
+
+    @RolesAllowed("/api/connected_platforms/view")
+    @GET
+    @Path("/user")
+    public Response getConnectedPlatforms(@Auth UserInfo ui) {
+        return Response.ok(connectedPlatformsService.getUserPlatforms(ui.getName())).build();
+    }
+
+    @RolesAllowed("/api/connected_platforms/add")
+    @POST
+    public Response addConnectedPlatform(@Auth UserInfo ui, @Valid ConnectedPlatformAddFrom from) {
+        connectedPlatformsService.addPlatform(ui, from.getName(), from.getType(), from.getUrl());
+        return Response.ok().build();
+    }
+
+    @RolesAllowed("/api/connected_platforms/disconnect")
+    @DELETE
+    @Path("{name}")
+    public Response disconnectPlatform(@Auth UserInfo ui, @PathParam("name") String platformName) {
+        connectedPlatformsService.disconnect(ui, platformName);
+        return Response.ok().build();
+    }
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/EnvironmentResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/EnvironmentResource.java
index b4b1418..84da439 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/EnvironmentResource.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/EnvironmentResource.java
@@ -20,6 +20,7 @@
 package com.epam.datalab.backendapi.resources;
 
 import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.ExploratoryImageCreateFormAdminDTO;
 import com.epam.datalab.backendapi.service.EnvironmentService;
 import com.google.inject.Inject;
 import io.dropwizard.auth.Auth;
@@ -27,6 +28,8 @@
 import org.hibernate.validator.constraints.NotEmpty;
 
 import javax.annotation.security.RolesAllowed;
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
@@ -35,6 +38,7 @@
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
 
 @Path("environment")
 @Slf4j
@@ -59,6 +63,18 @@
     @POST
     @Consumes(MediaType.TEXT_PLAIN)
     @Produces(MediaType.APPLICATION_JSON)
+    @Path("start/{projectName}/{exploratoryName}")
+    public Response startNotebook(@Auth UserInfo userInfo, @NotEmpty String user,
+                                  @PathParam("projectName") String projectName,
+                                  @PathParam("exploratoryName") String exploratoryName) {
+        log.info("Admin {} is starting notebook {} of user {}", userInfo.getName(), exploratoryName, user);
+        environmentService.startExploratory(userInfo, user, projectName, exploratoryName);
+        return Response.ok().build();
+    }
+
+    @POST
+    @Consumes(MediaType.TEXT_PLAIN)
+    @Produces(MediaType.APPLICATION_JSON)
     @Path("stop/{projectName}/{exploratoryName}")
     public Response stopNotebook(@Auth UserInfo userInfo, @NotEmpty String user,
                                  @PathParam("projectName") String projectName,
@@ -107,4 +123,15 @@
         environmentService.terminateComputational(userInfo, user, projectName, exploratoryName, computationalName);
         return Response.ok().build();
     }
+
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("createImage/{projectName}/{exploratoryName}")
+    public Response createImage(@Auth UserInfo userInfo,
+                                @Valid @NotNull ExploratoryImageCreateFormAdminDTO form) {
+        log.info("Admin {} is creating an image of exploratory {} of user {}", userInfo.getName(), form.getNotebookName(), form.getUser());
+        environmentService.createImage(userInfo, form.getUser(), form.getProjectName(), form.getNotebookName(), form.getName(), form.getDescription());
+        return Response.ok().build();
+    }
 }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ExploratoryResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ExploratoryResource.java
index 39bfb89..f96d578 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ExploratoryResource.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ExploratoryResource.java
@@ -22,9 +22,12 @@
 import com.epam.datalab.auth.UserInfo;
 import com.epam.datalab.backendapi.resources.dto.ExploratoryActionFormDTO;
 import com.epam.datalab.backendapi.resources.dto.ExploratoryCreateFormDTO;
+import com.epam.datalab.backendapi.resources.dto.ImageInfoRecord;
 import com.epam.datalab.backendapi.roles.RoleType;
 import com.epam.datalab.backendapi.roles.UserRoles;
 import com.epam.datalab.backendapi.service.ExploratoryService;
+import com.epam.datalab.backendapi.service.ImageExploratoryService;
+import com.epam.datalab.backendapi.service.impl.ImageExploratoryServiceImpl;
 import com.epam.datalab.dto.aws.computational.ClusterConfig;
 import com.epam.datalab.exceptions.DatalabException;
 import com.epam.datalab.model.exploratory.Exploratory;
@@ -51,9 +54,12 @@
 
     private final ExploratoryService exploratoryService;
 
+    private final ImageExploratoryService imageExploratoryService;
+
     @Inject
-    public ExploratoryResource(ExploratoryService exploratoryService) {
+    public ExploratoryResource(ExploratoryService exploratoryService, ImageExploratoryService imageExploratoryService) {
         this.exploratoryService = exploratoryService;
+        this.imageExploratoryService = imageExploratoryService;
     }
 
     @GET
@@ -79,6 +85,12 @@
             throw new DatalabException("You do not have the privileges to create a " + formDTO.getTemplateName());
         }
 
+        if(imageExploratoryService.imageExistInProject(formDTO.getImageName(), formDTO.getProject())
+                && !imageExploratoryService.canCreateFromImage(userInfo, formDTO.getImageName(),formDTO.getProject() , formDTO.getEndpoint())){
+            log.warn("Unauthorized attempt to create notebook from image  {} by user {}", formDTO.getImageName(), userInfo.getName());
+            throw new DatalabException("You do not have the privileges to create notebook from image " + formDTO.getImageName());
+        }
+
         String uuid = exploratoryService.create(userInfo, getExploratory(formDTO), formDTO.getProject(), formDTO.getName());
         return Response.ok(uuid).build();
 
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ImageExploratoryResource.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ImageExploratoryResource.java
index 95dcdb4..739ee93 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ImageExploratoryResource.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/ImageExploratoryResource.java
@@ -21,22 +21,16 @@
 
 import com.epam.datalab.auth.UserInfo;
 import com.epam.datalab.backendapi.domain.RequestId;
-import com.epam.datalab.backendapi.resources.dto.ExploratoryImageCreateFormDTO;
-import com.epam.datalab.backendapi.resources.dto.ImageInfoRecord;
+import com.epam.datalab.backendapi.resources.dto.*;
 import com.epam.datalab.backendapi.service.ImageExploratoryService;
 import com.google.inject.Inject;
 import io.dropwizard.auth.Auth;
 import lombok.extern.slf4j.Slf4j;
 
+import javax.annotation.security.RolesAllowed;
 import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.POST;
-import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
-import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
+import javax.ws.rs.*;
 import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
@@ -53,7 +47,6 @@
 @Produces(MediaType.APPLICATION_JSON)
 @Slf4j
 public class ImageExploratoryResource {
-    private static final String AUDIT_MESSAGE = "Create image: %s";
 
     private final ImageExploratoryService imageExploratoryService;
     private final RequestId requestId;
@@ -70,7 +63,7 @@
                                 @Context UriInfo uriInfo) {
         log.debug("Creating an image {} for user {}", formDTO, ui.getName());
         String uuid = imageExploratoryService.createImage(ui, formDTO.getProjectName(), formDTO.getNotebookName(),
-                formDTO.getName(), formDTO.getDescription(), String.format(AUDIT_MESSAGE, formDTO.getName()));
+                formDTO.getName(), formDTO.getDescription());
         requestId.put(ui.getName(), uuid);
 
         final URI imageUri = UriBuilder.fromUri(uriInfo.getRequestUri())
@@ -85,9 +78,8 @@
                               @QueryParam("project") String project,
                               @QueryParam("endpoint") String endpoint) {
         log.debug("Getting images for user {}, project {}", ui.getName(), project);
-        final List<ImageInfoRecord> images = imageExploratoryService.getNotFailedImages(ui.getName(), dockerImage,
-                project, endpoint);
-        return Response.ok(images).build();
+        return Response.ok(imageExploratoryService.getNotFailedImages(ui, dockerImage,
+                project, endpoint)).build();
     }
 
     @GET
@@ -98,6 +90,24 @@
         return Response.ok(images).build();
     }
 
+
+    @GET
+    @Path("user")
+    public Response getImagesForUser(@Auth UserInfo ui) {
+        log.debug("Getting images for user {}", ui.getName());
+        final ImagesPageInfo images = imageExploratoryService.getImagesOfUser(ui,null);
+        return Response.ok(images).build();
+    }
+
+    @POST
+    @Path("user")
+    public Response getImagesForUser(@Auth UserInfo ui, @Valid @NotNull ImageFilter imageFilter) {
+        log.debug("Getting images for user {} with filter {}", ui.getName(), imageFilter);
+        final ImagesPageInfo images = imageExploratoryService.getImagesOfUser(ui, imageFilter);
+        return Response.ok(images).build();
+    }
+
+
     @GET
     @Path("{name}")
     public Response getImage(@Auth UserInfo ui,
@@ -107,4 +117,44 @@
         log.debug("Getting image with name {} for user {}", name, ui.getName());
         return Response.ok(imageExploratoryService.getImage(ui.getName(), name, project, endpoint)).build();
     }
+
+    @RolesAllowed("/api/image/share")
+    @POST
+    @Path("share")
+    public Response shareImage(@Auth UserInfo ui, @Valid @NotNull ImageShareDTO dto) {
+        log.debug("Sharing user image {} with project {} groups", dto.getImageName(), dto.getProjectName());
+        imageExploratoryService.updateImageSharing(ui, dto);
+        return Response.ok(imageExploratoryService.getImagesOfUser(ui,null)).build();
+    }
+
+    @RolesAllowed("/api/image/terminate")
+    @DELETE
+    @Path("/{projectName}/{endpoint}/{imageName}/terminate")
+    public Response terminateUserImage(@Auth UserInfo ui,
+                                       @PathParam("imageName") String imageName,
+                                       @PathParam("projectName") String projectName,
+                                       @PathParam("endpoint") String endpoint) {
+        log.debug("Terminating  image {} of user {} groups", imageName, ui.getName());
+        imageExploratoryService.terminateImage(ui,projectName,endpoint,imageName);
+        return Response.ok(imageExploratoryService.getImagesOfUser(ui,null)).build();
+    }
+
+    @GET
+    @Path("sharing_info/{imageName}/{projectName}/{endpoint}")
+    public Response getSharingInfo(@Auth UserInfo ui,
+                                   @PathParam("imageName") String imageName,
+                                   @PathParam("projectName") String projectName,
+                                   @PathParam("endpoint") String endpoint){
+        return Response.ok(imageExploratoryService.getSharingInfo(ui.getName(),imageName,projectName, endpoint)).build();
+    }
+
+    @GET
+    @Path("share_autocomplete/{imageName}/{projectName}/{endpoint}")
+    public Response getUsersAndGroups(@Auth UserInfo userInfo,
+                                      @PathParam("imageName") String imageName,
+                                      @PathParam("projectName") String projectName,
+                                      @PathParam("endpoint") String endpoint,
+                                      @NotNull @QueryParam("value") String value){
+        return Response.ok(imageExploratoryService.getUsersAndGroupsForSharing(userInfo.getName(),imageName, projectName, endpoint, value)).build();
+    }
 }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/azure/ComputationalResourceAzure.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/azure/ComputationalResourceAzure.java
index f1582f2..49abd6a 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/azure/ComputationalResourceAzure.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/azure/ComputationalResourceAzure.java
@@ -20,17 +20,22 @@
 package com.epam.datalab.backendapi.resources.azure;
 
 import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.conf.SelfServiceApplicationConfiguration;
 import com.epam.datalab.backendapi.resources.dto.SparkStandaloneClusterCreateForm;
+import com.epam.datalab.backendapi.resources.dto.azure.AzureComputationalCreateForm;
 import com.epam.datalab.backendapi.roles.RoleType;
 import com.epam.datalab.backendapi.roles.UserRoles;
 import com.epam.datalab.backendapi.service.ComputationalService;
 import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.dto.azure.computational.AzureComputationalResource;
+import com.epam.datalab.dto.base.DataEngineType;
 import com.epam.datalab.exceptions.DatalabException;
 import com.google.inject.Inject;
 import io.dropwizard.auth.Auth;
 import io.swagger.v3.oas.annotations.Parameter;
 import lombok.extern.slf4j.Slf4j;
 
+import javax.management.relation.Role;
 import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
 import javax.ws.rs.Consumes;
@@ -44,6 +49,7 @@
 import javax.ws.rs.core.Response;
 import java.util.List;
 
+import static com.epam.datalab.dto.UserInstanceStatus.CREATING;
 import static com.epam.datalab.rest.contracts.ComputationalAPI.AUDIT_COMPUTATIONAL_RECONFIGURE_MESSAGE;
 import static com.epam.datalab.rest.contracts.ComputationalAPI.AUDIT_MESSAGE;
 
@@ -55,11 +61,16 @@
 @Produces(MediaType.APPLICATION_JSON)
 @Slf4j
 public class ComputationalResourceAzure {
+
+    private final SelfServiceApplicationConfiguration configuration;
+
     private final ComputationalService computationalService;
 
     @Inject
-    public ComputationalResourceAzure(ComputationalService computationalService) {
+    public ComputationalResourceAzure(ComputationalService computationalService,
+                                      SelfServiceApplicationConfiguration configuration) {
         this.computationalService = computationalService;
+        this.configuration = configuration;
     }
 
     @GET
@@ -69,6 +80,37 @@
         return Response.ok(computationalService.getComputationalNamesAndTemplates(userInfo, project, endpoint)).build();
     }
 
+    @PUT
+    @Path("dataengine-service")
+    public Response createDataEngineService(@Auth @Parameter(hidden = true) UserInfo userInfo,
+                                            @Parameter @Valid @NotNull AzureComputationalCreateForm form) {
+        log.debug("Create computational resources for {} | form is {}", userInfo.getName(), form);
+
+        if (DataEngineType.CLOUD_SERVICE == DataEngineType.fromDockerImageName(form.getImage())) {
+
+            validate(userInfo, form);
+
+            AzureComputationalResource azureComputationalResource = AzureComputationalResource.builder()
+                    .computationalName(form.getName())
+                    .imageName(form.getImage())
+                    .templateName(form.getTemplateName())
+                    .status(CREATING.toString())
+                    .masterShape(form.getMasterInstanceType())
+                    .slaveShape(form.getSlaveInstanceType())
+                    .totalInstanceCount(Integer.parseInt(form.getInstanceCount()))
+                    .config(form.getConfig())
+                    .version(form.getVersion())
+                    .build();
+
+            boolean resourceAdded = computationalService.createDataEngineService(userInfo, form.getName(), form, azureComputationalResource
+                    , form.getProject(), getAuditInfo(form.getNotebookName()));
+            return resourceAdded ? Response.ok().build() : Response.status(Response.Status.FOUND).build();
+        }
+
+        throw new IllegalArgumentException("Malformed image " + form.getImage());
+    }
+
+
     /**
      * Asynchronously creates computational Spark cluster.
      *
@@ -175,6 +217,26 @@
         return Response.ok(computationalService.getClusterConfig(userInfo, projectName, exploratoryName, computationalName)).build();
     }
 
+    private void validate(UserInfo userInfo, AzureComputationalCreateForm formDTO) {
+        if (!UserRoles.checkAccess(userInfo, RoleType.COMPUTATIONAL, formDTO.getImage(), userInfo.getRoles())) {
+            log.warn("Unauthorized attempt to create a {} by user {}", formDTO.getImage(), userInfo.getName());
+            throw new DatalabException("You do not have the privileges to create a " + formDTO.getTemplateName());
+        }
+
+        int slaveInstanceCount = Integer.parseInt(formDTO.getInstanceCount());
+        if (slaveInstanceCount < configuration.getMinHDInsightInstanceCount() || slaveInstanceCount > configuration.getMaxHDInsightInstanceCount()) {
+
+            log.debug("Creating computational resource {} for user {} fail: Limit exceeded to creation slave " +
+                            "instances. Minimum is {}, maximum is {}",
+                    formDTO.getName(), userInfo.getName(), configuration.getMinHDInsightInstanceCount(),
+                    configuration.getMaxHDInsightInstanceCount());
+            throw new DatalabException("Limit exceeded to creation slave instances. Minimum is " +
+                    configuration.getMinHDInsightInstanceCount() + ", maximum is " + configuration.getMaxHDInsightInstanceCount() +
+                    ".");
+        }
+
+    }
+
     private String getAuditInfo(String exploratoryName) {
         return String.format(AUDIT_MESSAGE, exploratoryName);
     }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ImageCallback.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ImageCallback.java
index 587c8ea..a604bfc 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ImageCallback.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ImageCallback.java
@@ -51,8 +51,13 @@
     public Response imageCreateStatus(ImageCreateStatusDTO dto) {
         log.debug("Updating status of image {} for user {} to {}", dto.getName(), dto.getUser(), dto);
         requestId.remove(dto.getRequestId());
-        imageExploratoryService.finishImageCreate(getImage(dto), dto.getExploratoryName(), dto.getImageCreateDTO()
-                .getIp());
+        if(dto.getImageCreateDTO().getStatus() == ImageStatus.TERMINATED){
+            imageExploratoryService.finishTerminateImage(dto.getName(), dto.getProject(), dto.getEndpoint());
+        } else {
+            imageExploratoryService.finishImageCreate(getImage(dto), dto.getExploratoryName(), dto.getImageCreateDTO()
+                    .getIp());
+        }
+
         return Response.status(Response.Status.CREATED).build();
     }
 
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ProjectCallback.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ProjectCallback.java
index 23459ea..7e6aea1 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ProjectCallback.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/callback/ProjectCallback.java
@@ -78,7 +78,8 @@
 
     private void saveGpuForProject(ProjectResult projectResult, String projectName) {
         try {
-            if (projectResult.getEdgeInfo().getGpuList() != null) {
+            if (projectResult.getEdgeInfo().getGpuList() != null
+                    && !gpuDAO.getGPUByProjectName(projectName).isPresent()) {
                 List<String> gpuList = projectResult.getEdgeInfo().getGpuList();
                 log.info("Adding edgeGpu with gpu_types: {}, for project: {}", gpuList, projectName);
                 gpuDAO.create(new EdgeGPU(projectName, gpuList));
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/AuditFilter.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/AuditFilter.java
new file mode 100644
index 0000000..c52976d
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/AuditFilter.java
@@ -0,0 +1,52 @@
+/*
+     * Licensed to the Apache Software Foundation (ASF) under one
+     * or more contributor license agreements.  See the NOTICE file
+     * distributed with this work for additional information
+     * regarding copyright ownership.  The ASF licenses this file
+     * to you under the Apache License, Version 2.0 (the
+     * "License"); you may not use this file except in compliance
+     * with the License.  You may obtain a copy of the License at
+     *
+     *   http://www.apache.org/licenses/LICENSE-2.0
+     *
+     * Unless required by applicable law or agreed to in writing,
+     * software distributed under the License is distributed on an
+     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+     * KIND, either express or implied.  See the License for the
+     * specific language governing permissions and limitations
+     * under the License.
+     */
+
+package com.epam.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.NonNull;
+
+import java.util.List;
+
+@Data
+@NoArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class AuditFilter {
+    @NonNull
+    List<String> users;
+    @NonNull
+    List<String> projects;
+    @NonNull
+    List<String> resourceNames;
+    @NonNull
+    List<String> resourceTypes;
+    @JsonProperty("date_start")
+    String dateStart;
+    @JsonProperty("date_end")
+    String dateEnd;
+    @JsonProperty("page_number")
+    int pageNumber;
+    @JsonProperty("page_size")
+    int pageSize;
+    @JsonProperty("locale")
+    String locale;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ConnectedPlatformAddFrom.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ConnectedPlatformAddFrom.java
new file mode 100644
index 0000000..9b3a980
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ConnectedPlatformAddFrom.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package com.epam.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+import lombok.NonNull;
+import org.hibernate.validator.constraints.NotBlank;
+import org.hibernate.validator.constraints.URL;
+
+import javax.validation.Valid;
+import javax.validation.constraints.Size;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ConnectedPlatformAddFrom {
+    private static final String URL_REGEXP_VALIDATION = "^(http(s)?)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]";
+    @NotBlank(message = "field cannot be empty")
+    @Size(min = 1, max = 6)
+    private final String name;
+    @URL(regexp = URL_REGEXP_VALIDATION, message = "field is in improper format!")
+    private final String url;
+    @NonNull
+    @Valid
+    private final ConnectedPlatformType type;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ConnectedPlatformDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ConnectedPlatformDTO.java
new file mode 100644
index 0000000..95149ca
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ConnectedPlatformDTO.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ConnectedPlatformDTO {
+    private final String name;
+    private final ConnectedPlatformType type;
+    private final String user;
+    private final String url;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ConnectedPlatformType.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ConnectedPlatformType.java
new file mode 100644
index 0000000..7f36233
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ConnectedPlatformType.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.resources.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+@Getter
+@AllArgsConstructor
+public enum ConnectedPlatformType {
+    MLFLOW("MLflow");
+
+    private final String name;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ConnectedPlatformsInfo.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ConnectedPlatformsInfo.java
new file mode 100644
index 0000000..ed5463c
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ConnectedPlatformsInfo.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.util.List;
+
+@AllArgsConstructor
+@Builder
+@EqualsAndHashCode
+@ToString
+public class ConnectedPlatformsInfo {
+    @JsonProperty
+    private List<ConnectedPlatformDTO> userPlatforms;
+    @JsonProperty
+    private List<String> types;
+    @JsonProperty
+    private List<String> platformNames;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryImageCreateFormAdminDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryImageCreateFormAdminDTO.java
new file mode 100644
index 0000000..f829988
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryImageCreateFormAdminDTO.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.resources.dto;
+
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.ToString;
+import org.hibernate.validator.constraints.NotBlank;
+
+@Data
+@ToString
+public class ExploratoryImageCreateFormAdminDTO {
+    @NotBlank
+    private String user;
+    @NotBlank
+    @JsonProperty("imageName")
+    private String name;
+    @NotBlank
+    @JsonProperty("exploratory_name")
+    private String notebookName;
+    @NotBlank
+    @JsonProperty("project_name")
+    private String projectName;
+    private final String description;
+}
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/HealthStatusPageDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/HealthStatusPageDTO.java
index 9db1cfc..2b2a23f 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/HealthStatusPageDTO.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/HealthStatusPageDTO.java
@@ -47,6 +47,8 @@
     private boolean projectAssigned;
     @JsonProperty
     private BucketBrowser bucketBrowser;
+    @JsonProperty
+    private ConnectedPlatforms connectedPlatforms;
 
     @Builder
     @Data
@@ -56,4 +58,12 @@
         private final boolean download;
         private final boolean delete;
     }
+
+    @Builder
+    @Data
+    public static class ConnectedPlatforms {
+        private final boolean view;
+        private final boolean add;
+        private final boolean disconnect;
+    }
 }
\ No newline at end of file
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageFilter.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageFilter.java
new file mode 100644
index 0000000..3ee650d
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageFilter.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.resources.dto;
+
+import com.epam.datalab.dto.exploratory.ImageSharingStatus;
+import com.epam.datalab.dto.exploratory.ImageStatus;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.NonNull;
+
+import java.util.HashSet;
+import java.util.Set;
+
+@Data
+@NoArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ImageFilter {
+    @NonNull
+    private String imageName = "";
+    @NonNull
+    private Set<ImageStatus> statuses = new HashSet<>();
+    @NonNull
+    private Set<String> endpoints = new HashSet<>();
+    @NonNull
+    private Set<String> templateNames = new HashSet<>();
+    @NonNull
+    private Set<ImageSharingStatus> sharingStatuses = new HashSet<>();
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageFilterFormData.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageFilterFormData.java
new file mode 100644
index 0000000..46a2081
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageFilterFormData.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.resources.dto;
+
+import com.epam.datalab.dto.exploratory.ImageSharingStatus;
+import com.epam.datalab.dto.exploratory.ImageStatus;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.NonNull;
+
+
+import java.util.Set;
+
+@Data
+@NoArgsConstructor
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ImageFilterFormData {
+    @NonNull
+    private Set<String> imageNames;
+    @NonNull
+    private Set<ImageStatus> statuses;
+    @NonNull
+    private Set<String> endpoints;
+    @NonNull
+    private Set<String> templateNames;
+    @NonNull
+    private Set<ImageSharingStatus> sharingStatuses;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageInfoDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageInfoDTO.java
new file mode 100644
index 0000000..f45085b
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageInfoDTO.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package com.epam.datalab.backendapi.resources.dto;
+
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.SharedWith;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
+import com.epam.datalab.dto.exploratory.ImageSharingStatus;
+import com.epam.datalab.dto.exploratory.ImageStatus;
+import com.epam.datalab.model.library.Library;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+@Data
+@Builder
+@AllArgsConstructor
+public class ImageInfoDTO {
+    private String name;
+    private Date timestamp;
+    private String description;
+    private String project;
+    private String endpoint;
+    private String user;
+    private String application;
+    private String templateName;
+    private String instanceName;
+    private CloudProvider cloudProvider;
+    private String dockerImage;
+    private String fullName;
+    private ImageStatus status;
+    private ImageSharingStatus sharingStatus;
+    private ImageUserPermissions imageUserPermissions;
+    private SharedWith sharedWith;
+    private List<ClusterConfig> clusterConfig;
+    private String exploratoryURL;
+    private List<Library> libraries;
+    private Map<String, List<Library>> computationalLibraries;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageInfoRecord.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageInfoRecord.java
index 18692c3..a4472e1 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageInfoRecord.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageInfoRecord.java
@@ -19,19 +19,37 @@
 
 package com.epam.datalab.backendapi.resources.dto;
 
+import com.epam.datalab.cloud.CloudProvider;
+import com.epam.datalab.dto.SharedWith;
+import com.epam.datalab.dto.aws.computational.ClusterConfig;
 import com.epam.datalab.dto.exploratory.ImageStatus;
+import com.epam.datalab.model.library.Library;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 import lombok.Data;
 
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
 @Data
 @JsonIgnoreProperties(ignoreUnknown = true)
 public class ImageInfoRecord {
     private final String name;
+    private final Date timestamp;
     private final String description;
     private final String project;
     private final String endpoint;
     private final String user;
     private final String application;
+    private final String templateName;
+    private final String instanceName;
+    private final CloudProvider cloudProvider;
+    private final String dockerImage;
     private final String fullName;
     private final ImageStatus status;
+    private final SharedWith sharedWith;
+    private final List<ClusterConfig> clusterConfig;
+    private final String exploratoryURL;
+    private final List<Library> libraries;
+    private final Map<String, List<Library>> computationalLibraries;
 }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageShareDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageShareDTO.java
new file mode 100644
index 0000000..25634c3
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageShareDTO.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+import java.util.Set;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ImageShareDTO {
+    private final String imageName;
+    private final String projectName;
+    private final String endpoint;
+    private final Set<SharedWithDTO> sharedWith;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageUserPermissions.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageUserPermissions.java
new file mode 100644
index 0000000..1de9ec2
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImageUserPermissions.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package com.epam.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ImageUserPermissions {
+    private final boolean canShare;
+    private final boolean canTerminate;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImagesPageInfo.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImagesPageInfo.java
new file mode 100644
index 0000000..0589d74
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ImagesPageInfo.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.util.List;
+import java.util.Map;
+
+@AllArgsConstructor
+@Builder
+@EqualsAndHashCode
+@ToString
+public class ImagesPageInfo {
+    @JsonProperty
+    private List<ProjectImagesInfo> projectImagesInfos;
+    @JsonProperty
+    private ImageFilter imageFilter;
+    @JsonProperty
+    private ImageFilterFormData filterData;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ProjectImagesInfo.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ProjectImagesInfo.java
new file mode 100644
index 0000000..46dfe66
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ProjectImagesInfo.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.*;
+
+import java.util.List;
+
+@AllArgsConstructor
+@Builder
+@EqualsAndHashCode
+@ToString
+@Data
+public class ProjectImagesInfo {
+    @JsonProperty
+    private String project;
+    @JsonProperty
+    private List<ImageInfoDTO> images;
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/SharedWithDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/SharedWithDTO.java
new file mode 100644
index 0000000..8dcdf6e
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/SharedWithDTO.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.*;
+
+import javax.annotation.Nonnull;
+import java.util.Comparator;
+
+@Getter
+@Setter
+@ToString
+@EqualsAndHashCode
+@JsonIgnoreProperties(ignoreUnknown = true)
+@AllArgsConstructor
+public class SharedWithDTO implements Comparable<SharedWithDTO>{
+    private Type type;
+    private String value;
+
+    public enum Type{
+        GROUP,
+        USER
+    }
+
+    @Override
+    public int compareTo(@Nonnull SharedWithDTO o) {
+        return Comparator.comparing(SharedWithDTO::getType)
+                .thenComparing(SharedWithDTO::getValue)
+                .compare(this, o);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/SharingInfo.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/SharingInfo.java
new file mode 100644
index 0000000..89d3180
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/SharingInfo.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package com.epam.datalab.backendapi.resources.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Set;
+import java.util.TreeSet;
+@Getter
+@Setter
+public class SharingInfo {
+    public Set<SharedWithDTO> sharedWith = new TreeSet<>();
+    public Set<SharedWithDTO> canBeSharedWith = new TreeSet<>();
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UserRoleDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UserRoleDTO.java
index 62514f3..cfaa82e 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UserRoleDTO.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/UserRoleDTO.java
@@ -42,6 +42,7 @@
     private Set<String> pages;
     private Set<String> computationals;
     private Set<String> exploratories;
+    private Set<String> images;
     @JsonProperty("exploratory_shapes")
     private Set<String> exploratoryShapes;
     @JsonProperty("computational_shapes")
@@ -51,14 +52,16 @@
     private enum Type {
         NOTEBOOK,
         COMPUTATIONAL,
+        IMAGE,
         NOTEBOOK_SHAPE,
         COMPUTATIONAL_SHAPE,
+        CONNECTED_PLATFORMS,
         BILLING,
         BUCKET_BROWSER,
         ADMINISTRATION,
     }
 
     public static List<Type> cloudSpecificTypes() {
-        return Arrays.asList(Type.NOTEBOOK, Type.COMPUTATIONAL, Type.NOTEBOOK_SHAPE, Type.COMPUTATIONAL_SHAPE);
+        return Arrays.asList(Type.NOTEBOOK, Type.COMPUTATIONAL, Type.IMAGE, Type.NOTEBOOK_SHAPE, Type.COMPUTATIONAL_SHAPE);
     }
 }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/azure/AzureComputationalCreateForm.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/azure/AzureComputationalCreateForm.java
new file mode 100644
index 0000000..d85d63e
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/azure/AzureComputationalCreateForm.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.resources.dto.azure;
+
+import com.epam.datalab.backendapi.resources.dto.ComputationalCreateFormDTO;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.hibernate.validator.constraints.NotBlank;
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@JsonIgnoreProperties
+public class AzureComputationalCreateForm extends ComputationalCreateFormDTO {
+
+    @NotBlank
+    @JsonProperty("hdinsight_instance_count")
+    private String instanceCount;
+
+    @NotBlank
+    @JsonProperty("hdinsight_master_instance_type")
+    private String masterInstanceType;
+    @NotBlank
+    @JsonProperty("hdinsight_slave_instance_type")
+    private String slaveInstanceType;
+    @NotBlank
+    @JsonProperty("hdinsight_version")
+    private String version;
+
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/azure/AzureHDInsightConfiguration.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/azure/AzureHDInsightConfiguration.java
new file mode 100644
index 0000000..54dcf79
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/azure/AzureHDInsightConfiguration.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.resources.dto.azure;
+
+import com.epam.datalab.backendapi.resources.dto.ComputationalCreateFormDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Data;
+import org.hibernate.validator.constraints.NotBlank;
+
+@Data
+@Builder
+public class AzureHDInsightConfiguration  {
+    @NotBlank
+    @JsonProperty("min_hdinsight_instance_count")
+    private int minHdinsightInstanceCount;
+    @NotBlank
+    @JsonProperty("max_hdinsight_instance_count")
+    private int maxHdinsightInstanceCount;
+
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/roles/RoleType.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/roles/RoleType.java
index 998e01f..1b27567 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/roles/RoleType.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/roles/RoleType.java
@@ -25,6 +25,7 @@
 public enum RoleType {
     COMPUTATIONAL("computationals"),
     EXPLORATORY("exploratories"),
+    IMAGE("images"),
     EXPLORATORY_SHAPES("exploratory_shapes"),
     COMPUTATIONAL_SHAPES("computational_shapes"),
     PAGE("pages");
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/CheckInfrastructureStatusScheduler.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/CheckInfrastructureStatusScheduler.java
index ab11001..40ae7f4 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/CheckInfrastructureStatusScheduler.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/schedulers/CheckInfrastructureStatusScheduler.java
@@ -73,6 +73,7 @@
 
     @Override
     public void execute(JobExecutionContext context) {
+        log.info("Trying to update infrastructure statuses");
         UserInfo serviceUser = securityService.getServiceAccountInfo("admin");
 
         List<String> activeEndpoints = endpointService.getEndpointsWithStatus(EndpointDTO.EndpointStatus.ACTIVE)
@@ -80,7 +81,8 @@
                 .map(EndpointDTO::getName)
                 .collect(Collectors.toList());
 
-        List<UserInstanceDTO> userInstanceDTOS = exploratoryDAO.fetchExploratoriesByEndpointWhereStatusIn(activeEndpoints, statusesToCheck, Boolean.TRUE);
+        List<UserInstanceDTO> userInstanceDTOS = exploratoryDAO.fetchExploratoriesByEndpointWhereStatusIn(activeEndpoints, statusesToCheck, Boolean.TRUE)
+        .stream().filter(e -> e.getInstanceId() != null).collect(Collectors.toList());
 
         Map<String, List<EnvResource>> exploratoryAndSparkInstances = userInstanceDTOS
                 .stream()
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/AuditService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/AuditService.java
index 6dc4ab5..b80d362 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/AuditService.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/AuditService.java
@@ -22,6 +22,9 @@
 import com.epam.datalab.backendapi.domain.AuditCreateDTO;
 import com.epam.datalab.backendapi.domain.AuditDTO;
 import com.epam.datalab.backendapi.domain.AuditPaginationDTO;
+import com.epam.datalab.backendapi.domain.AuditReport;
+import com.epam.datalab.backendapi.resources.dto.AuditFilter;
+import com.epam.datalab.model.StringList;
 
 import java.util.List;
 
@@ -31,4 +34,9 @@
     void save(String user, AuditCreateDTO audit);
 
     List<AuditPaginationDTO> getAudit(List<String> users, List<String> projects, List<String> resourceNames, List<String> resourceTypes, String dateStart, String dateEnd, int pageNumber, int pageSize);
+
+    AuditReport getAuditReport(AuditFilter filter);
+
+    String downloadAuditReport(AuditFilter filter);
+
 }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ConnectedPlatformsService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ConnectedPlatformsService.java
new file mode 100644
index 0000000..a198548
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ConnectedPlatformsService.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.service;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.resources.dto.ConnectedPlatformDTO;
+import com.epam.datalab.backendapi.resources.dto.ConnectedPlatformType;
+import com.epam.datalab.backendapi.resources.dto.ConnectedPlatformsInfo;
+
+import java.util.List;
+
+public interface ConnectedPlatformsService {
+    ConnectedPlatformsInfo getUserPlatforms(String userName);
+    List<ConnectedPlatformDTO> getAll();
+
+    void addPlatform(UserInfo user, String name, ConnectedPlatformType type, String url);
+
+    void disconnect(UserInfo user, String name);
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/EnvironmentService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/EnvironmentService.java
index ad9fa3c..750d165 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/EnvironmentService.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/EnvironmentService.java
@@ -31,6 +31,10 @@
 
     List<UserResourceInfo> getAllEnv(UserInfo user);
 
+    void createImage(UserInfo userInfo, String user, String project, String exploratoryName, String imageName, String description);
+
+    void startExploratory(UserInfo userInfo, String user, String project, String exploratoryName);
+
     void stopAll();
 
     void stopEnvironmentWithServiceAccount(String user);
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ExploratoryService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ExploratoryService.java
index 3711c52..366b823 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ExploratoryService.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ExploratoryService.java
@@ -21,6 +21,7 @@
 
 
 import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.annotation.Info;
 import com.epam.datalab.backendapi.domain.ProjectDTO;
 import com.epam.datalab.backendapi.resources.dto.ExploratoryCreatePopUp;
 import com.epam.datalab.dto.UserInstanceDTO;
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ImageExploratoryService.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ImageExploratoryService.java
index fae72a3..5d78c28 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ImageExploratoryService.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/ImageExploratoryService.java
@@ -20,20 +20,44 @@
 package com.epam.datalab.backendapi.service;
 
 import com.epam.datalab.auth.UserInfo;
-import com.epam.datalab.backendapi.resources.dto.ImageInfoRecord;
+import com.epam.datalab.backendapi.resources.dto.*;
 import com.epam.datalab.model.exploratory.Image;
 
 import java.util.List;
+import java.util.Set;
 
 public interface ImageExploratoryService {
+    boolean imageExistInProject(String imageName, String project);
 
-    String createImage(UserInfo user, String project, String exploratoryName, String imageName, String imageDescription, String info);
+    String createImage(UserInfo user, String project, String exploratoryName, String imageName, String imageDescription);
+
+    void terminateImage(UserInfo user, String project, String endpoint, String imageName);
+
+    void finishTerminateImage(String imageName, String projectName, String endpoint);
 
     void finishImageCreate(Image image, String exploratoryName, String newNotebookIp);
 
-    List<ImageInfoRecord> getNotFailedImages(String user, String dockerImage, String project, String endpoint);
+    List<ImageInfoDTO> getNotFailedImages(UserInfo user, String dockerImage, String project, String endpoint);
 
     ImageInfoRecord getImage(String user, String name, String project, String endpoint);
 
+    ImageInfoRecord getImage(String name, String project, String endpoint);
+
     List<ImageInfoRecord> getImagesForProject(String project);
+
+    ImagesPageInfo getImagesOfUser(UserInfo user, ImageFilter imageFilter);
+
+    void updateImageSharing(UserInfo user, ImageShareDTO imageShareDTO);
+
+    List<ImageInfoRecord> getSharedImages(UserInfo user);
+
+    List<ImageInfoRecord> getSharedImages(UserInfo userInfo, String dockerImage, String project, String endpoint);
+
+    ImageUserPermissions getUserImagePermissions(UserInfo userInfo, ImageInfoRecord image);
+
+    SharingInfo getSharingInfo(String userName, String imageName, String project, String endpoint);
+
+    boolean canCreateFromImage(UserInfo userInfo, String imageName, String project, String endpoint);
+
+    Set<SharedWithDTO> getUsersAndGroupsForSharing(String userName, String imageName, String project, String endpoint, String value);
 }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/AuditServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/AuditServiceImpl.java
index 161bf2b..7cf21b2 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/AuditServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/AuditServiceImpl.java
@@ -20,12 +20,13 @@
 package com.epam.datalab.backendapi.service.impl;
 
 import com.epam.datalab.backendapi.dao.AuditDAO;
-import com.epam.datalab.backendapi.domain.AuditCreateDTO;
-import com.epam.datalab.backendapi.domain.AuditDTO;
-import com.epam.datalab.backendapi.domain.AuditPaginationDTO;
+import com.epam.datalab.backendapi.domain.*;
+import com.epam.datalab.backendapi.resources.dto.AuditFilter;
 import com.epam.datalab.backendapi.service.AuditService;
+import com.epam.datalab.backendapi.util.AuditUtils;
 import com.google.inject.Inject;
 
+import java.time.LocalDate;
 import java.util.List;
 
 import static com.epam.datalab.backendapi.domain.AuditActionEnum.FOLLOW_LINK;
@@ -60,4 +61,28 @@
                                              String dateStart, String dateEnd, int pageNumber, int pageSize) {
         return auditDAO.getAudit(users, projects, resourceNames, resourceTypes, dateStart, dateEnd, pageNumber, pageSize);
     }
+
+    @Override
+    public AuditReport getAuditReport(AuditFilter filter) {
+        List<AuditReportLine> auditReportLines = auditDAO.aggregateAuditReport(filter);
+        final LocalDate dateFrom = LocalDate.parse(filter.getDateStart());
+        final LocalDate dateTo = LocalDate.parse(filter.getDateEnd());
+        return AuditReport.builder()
+                .name("Audit Report")
+                .reportLines(auditReportLines)
+                .usageDateFrom(dateFrom)
+                .usageDateTo(dateTo)
+                .build();
+    }
+
+    public String downloadAuditReport(AuditFilter filter) {
+        List<AuditReportLine> auditReportLines = auditDAO.aggregateAuditReport(filter);
+        final LocalDate dateFrom = LocalDate.parse(filter.getDateStart());
+        final LocalDate dateTo = LocalDate.parse(filter.getDateEnd());
+        StringBuilder reportHead = new StringBuilder(AuditUtils.getFirstLine(dateFrom, dateTo,  filter.getLocale()));
+        reportHead.append(AuditUtils.getHeader());
+        auditReportLines.forEach(r -> reportHead.append(AuditUtils.printLine(r)));
+
+        return reportHead.toString();
+    }
 }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/BillingServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/BillingServiceImpl.java
index 97dafb8..c829bda 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/BillingServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/BillingServiceImpl.java
@@ -99,7 +99,9 @@
         List<BillingReportLine> billingReportLines = billingDAO.aggregateBillingData(filter)
                 .stream()
                 .peek(this::appendStatuses)
+                .peek(this::appendShapes)
                 .filter(bd -> CollectionUtils.isEmpty(filter.getStatuses()) || filter.getStatuses().contains(bd.getStatus()))
+                .peek(bd -> { if (bd.getShape() != null && bd.getShape().contains("null")) bd.setShape(null);})
                 .collect(Collectors.toList());
         
         final LocalDate min = billingReportLines.stream().min(Comparator.comparing(BillingReportLine::getUsageDateFrom)).map(BillingReportLine::getUsageDateFrom).orElse(null);
@@ -340,6 +342,26 @@
     }
 
     /**
+     * Appends shapes for computational resources
+     * @param br Billing report info for certain resource
+     */
+    private void appendShapes(BillingReportLine br) {
+        BillingResourceType resourceType = br.getResourceType();
+        if (BillingResourceType.COMPUTATIONAL == resourceType) {
+            String shape = "Master: 1 x %s Slave: %s x %s";
+            int numberOfMasterNodes = 1;
+            exploratoryService.getUserInstance(br.getUser(), br.getProject(), br.getExploratoryName(), true)
+                    .flatMap(ui -> ui.getResources()
+                            .stream()
+                            .filter(cr -> cr.getComputationalName().equals(br.getResourceName()))
+                            .findAny())
+                    .ifPresent(cr -> br.setShape(
+                            String.format(shape, cr.getMasterNodeShape(), cr.getTotalInstanceCount() - numberOfMasterNodes, cr.getSlaveNodeShape())
+                    ));
+        }
+    }
+
+    /**
      * @param userInfo user's properties for current session
      * @return true, if user has be billing role
      */
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ConnectedPlatformsServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ConnectedPlatformsServiceImpl.java
new file mode 100644
index 0000000..08884a9
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ConnectedPlatformsServiceImpl.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.service.impl;
+
+import com.epam.datalab.auth.UserInfo;
+import com.epam.datalab.backendapi.dao.ConnectedPlatformsDAO;
+import com.epam.datalab.backendapi.resources.dto.ConnectedPlatformDTO;
+import com.epam.datalab.backendapi.resources.dto.ConnectedPlatformType;
+import com.epam.datalab.backendapi.resources.dto.ConnectedPlatformsInfo;
+import com.epam.datalab.backendapi.service.ConnectedPlatformsService;
+import com.epam.datalab.exceptions.ResourceAlreadyExistException;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+@Singleton
+@Slf4j
+public class ConnectedPlatformsServiceImpl implements ConnectedPlatformsService {
+
+    private static final String CONNECTED_PLATFORM_NAME_EXIST = "Connected platform with name %s already exist";
+    private final ConnectedPlatformsDAO connectedPlatformsDAO;
+
+
+    @Inject
+    public ConnectedPlatformsServiceImpl(ConnectedPlatformsDAO connectedPlatformsDAO) {
+        this.connectedPlatformsDAO = connectedPlatformsDAO;
+    }
+
+
+    @Override
+    public ConnectedPlatformsInfo getUserPlatforms(String userName) {
+        List<String> platformNames = getAll().stream().map(ConnectedPlatformDTO::getName).collect(Collectors.toList());
+        List<String> platformTypes = Stream.of(ConnectedPlatformType.values()).map(ConnectedPlatformType::getName).collect(Collectors.toList());
+        return ConnectedPlatformsInfo.builder()
+                .userPlatforms(connectedPlatformsDAO.getUserPlatforms(userName))
+                .types(platformTypes)
+                .platformNames(platformNames)
+                .build();
+    }
+
+    @Override
+    public List<ConnectedPlatformDTO> getAll() {
+        return connectedPlatformsDAO.getAll();
+    }
+
+    @Override
+    public void addPlatform(UserInfo user, String name, ConnectedPlatformType type, String url) {
+        if(connectedPlatformsDAO.exist(name)){
+            log.error(String.format(CONNECTED_PLATFORM_NAME_EXIST,name));
+            throw new ResourceAlreadyExistException(String.format(CONNECTED_PLATFORM_NAME_EXIST,name));
+        }
+
+        connectedPlatformsDAO.addPlatform(ConnectedPlatformDTO.builder()
+                .name(name)
+                .url(url)
+                .user(user.getName())
+                .type(type)
+                .build());
+    }
+
+    @Override
+    public void disconnect(UserInfo user, String name) {
+        connectedPlatformsDAO.delete(user.getName(), name);
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/EnvironmentServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/EnvironmentServiceImpl.java
index 2f23861..822a0ee 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/EnvironmentServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/EnvironmentServiceImpl.java
@@ -20,9 +20,7 @@
 package com.epam.datalab.backendapi.service.impl;
 
 import com.epam.datalab.auth.UserInfo;
-import com.epam.datalab.backendapi.annotation.Project;
-import com.epam.datalab.backendapi.annotation.ProjectAdmin;
-import com.epam.datalab.backendapi.annotation.User;
+import com.epam.datalab.backendapi.annotation.*;
 import com.epam.datalab.backendapi.dao.EnvDAO;
 import com.epam.datalab.backendapi.dao.ExploratoryDAO;
 import com.epam.datalab.backendapi.dao.UserSettingsDAO;
@@ -65,19 +63,21 @@
     private final ComputationalService computationalService;
     private final SecurityService securityService;
     private final ProjectService projectService;
+    private final ImageExploratoryService imageExploratoryService;
 
     @Inject
     public EnvironmentServiceImpl(EnvDAO envDAO, UserSettingsDAO settingsDAO, ExploratoryDAO exploratoryDAO,
                                   ExploratoryService exploratoryService, ComputationalService computationalService,
-                                  SecurityService securityService, ProjectService projectService) {
-        this.envDAO = envDAO;
-        this.settingsDAO = settingsDAO;
-        this.exploratoryDAO = exploratoryDAO;
-        this.exploratoryService = exploratoryService;
-        this.computationalService = computationalService;
-        this.securityService = securityService;
-        this.projectService = projectService;
-    }
+        SecurityService securityService, ProjectService projectService, ImageExploratoryService imageExploratoryService) {
+            this.envDAO = envDAO;
+            this.settingsDAO = settingsDAO;
+            this.exploratoryDAO = exploratoryDAO;
+            this.exploratoryService = exploratoryService;
+            this.computationalService = computationalService;
+            this.securityService = securityService;
+            this.projectService = projectService;
+            this.imageExploratoryService = imageExploratoryService;
+        }
 
     @Override
     public List<UserDTO> getUsers() {
@@ -106,6 +106,18 @@
                 .collect(Collectors.toList());
     }
 
+    @ProjectAdmin
+    @Override
+    public void createImage(@User UserInfo userInfo, String user, @Project String project, String exploratoryName, String imageName, String description) {
+        imageExploratoryService.createImage(securityService.getUserInfoOffline(user), project, exploratoryName, imageName, description);
+    }
+
+    @ProjectAdmin
+    @Override
+    public void startExploratory(@User UserInfo userInfo, String user, @Project String project, String exploratoryName) {
+        exploratoryService.start(securityService.getServiceAccountInfo(user),exploratoryName,project,null);
+    }
+
     @Override
     public void stopAll() {
         log.debug("Stopping environment for all users...");
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ExploratoryServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ExploratoryServiceImpl.java
index 60d4c84..d20dfae 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ExploratoryServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ExploratoryServiceImpl.java
@@ -52,7 +52,7 @@
 import java.util.stream.Collectors;
 
 import static com.epam.datalab.backendapi.domain.AuditActionEnum.*;
-import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.NOTEBOOK;
+import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.INSTANCE;
 import static com.epam.datalab.dto.UserInstanceStatus.*;
 import static com.epam.datalab.rest.contracts.ExploratoryAPI.*;
 
@@ -92,26 +92,26 @@
     }
 
     @BudgetLimited
-    @Audit(action = START, type = NOTEBOOK)
+    @Audit(action = START, type = INSTANCE)
     @Override
     public String start(@User UserInfo userInfo, @ResourceName String exploratoryName, @Project String project, @Info String auditInfo) {
         return action(userInfo, userInfo.getName(), project, exploratoryName, EXPLORATORY_START, STARTING);
     }
 
-    @Audit(action = STOP, type = NOTEBOOK)
+    @Audit(action = STOP, type = INSTANCE)
     @Override
     public String stop(@User UserInfo userInfo, String resourceCreator, @Project String project, @ResourceName String exploratoryName, @Info String auditInfo) {
         return action(userInfo, resourceCreator, project, exploratoryName, EXPLORATORY_STOP, STOPPING);
     }
 
-    @Audit(action = TERMINATE, type = NOTEBOOK)
+    @Audit(action = TERMINATE, type = INSTANCE)
     @Override
     public String terminate(@User UserInfo userInfo, String resourceCreator, @Project String project, @ResourceName String exploratoryName, @Info String auditInfo) {
         return action(userInfo, resourceCreator, project, exploratoryName, EXPLORATORY_TERMINATE, TERMINATING);
     }
 
     @BudgetLimited
-    @Audit(action = CREATE, type = NOTEBOOK)
+    @Audit(action = CREATE, type = INSTANCE)
     @Override
     public String create(@User UserInfo userInfo, Exploratory exploratory, @Project String project, @ResourceName String exploratoryName) {
         boolean isAdded = false;
@@ -151,7 +151,7 @@
     }
 
     private boolean isDeepLearningOnAwsOrAzure(Exploratory exploratory, EndpointDTO endpointDTO) {
-        return exploratory.getVersion().equals("Deep Learning AMI (Ubuntu 18.04) Version 42.1") ||
+        return exploratory.getVersion().equals("Deep Learning AMI (Ubuntu 18.04) Version 60.2") ||
                 exploratory.getVersion().equals("microsoft-dsvm:ubuntu-1804:1804");
     }
 
@@ -170,7 +170,7 @@
                 });
     }
 
-    @Audit(action = RECONFIGURE, type = NOTEBOOK)
+    @Audit(action = RECONFIGURE, type = INSTANCE)
     @Override
     public void updateClusterConfig(@User UserInfo userInfo, @Project String project, @ResourceName String exploratoryName, List<ClusterConfig> config) {
         final String userName = userInfo.getName();
@@ -246,7 +246,7 @@
         return new ExploratoryCreatePopUp(userProjects, collect);
     }
 
-    @Audit(action = UPDATE, type = NOTEBOOK)
+    @Audit(action = UPDATE, type = INSTANCE)
     @Override
     public void updateAfterStatusCheck(@User UserInfo userInfo, @Project String project, String endpoint, @ResourceName String name,
                                        String instanceID, UserInstanceStatus status, @Info String auditInfo) {
@@ -292,7 +292,7 @@
         }
     }
 
-    @Audit(action = TERMINATE, type = NOTEBOOK)
+    @Audit(action = TERMINATE, type = INSTANCE)
     public void updateExploratoryComputeStatuses(@User UserInfo userInfo, @Project String project, @ResourceName String exploratoryName, UserInstanceStatus status, String resourceCreator) {
         updateExploratoryStatus(resourceCreator, project, exploratoryName, status);
         updateComputationalStatuses(userInfo.getName(), resourceCreator, project, exploratoryName, status);
@@ -422,16 +422,16 @@
                 .withGPUEnabled(exploratory.getEnabledGPU())
                 .withGPUType(exploratory.getGpuType());
         if (StringUtils.isNotBlank(exploratory.getImageName())) {
-            final List<LibInstallDTO> libInstallDtoList = getImageRelatedLibraries(userInfo, exploratory.getImageName(),
+            final List<LibInstallDTO> libInstallDtoList = getImageRelatedLibraries(exploratory.getImageName(),
                     project, exploratory.getEndpoint());
             userInstance.withLibs(libInstallDtoList);
         }
         return userInstance;
     }
 
-    private List<LibInstallDTO> getImageRelatedLibraries(UserInfo userInfo, String imageFullName, String project,
+    private List<LibInstallDTO> getImageRelatedLibraries(String imageName, String project,
                                                          String endpoint) {
-        final List<Library> libraries = imageExploratoryDao.getLibraries(userInfo.getName(), imageFullName, project,
+        final List<Library> libraries = imageExploratoryDao.getLibraries(imageName, project,
                 endpoint, LibStatus.INSTALLED);
         return toLibInstallDtoList(libraries);
     }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ImageExploratoryServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ImageExploratoryServiceImpl.java
index 8c68021..62f3f27 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ImageExploratoryServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ImageExploratoryServiceImpl.java
@@ -25,20 +25,22 @@
 import com.epam.datalab.backendapi.annotation.Project;
 import com.epam.datalab.backendapi.annotation.ResourceName;
 import com.epam.datalab.backendapi.annotation.User;
-import com.epam.datalab.backendapi.dao.ExploratoryDAO;
-import com.epam.datalab.backendapi.dao.ExploratoryLibDAO;
-import com.epam.datalab.backendapi.dao.ImageExploratoryDAO;
+import com.epam.datalab.backendapi.dao.*;
 import com.epam.datalab.backendapi.domain.EndpointDTO;
 import com.epam.datalab.backendapi.domain.ProjectDTO;
-import com.epam.datalab.backendapi.resources.dto.ImageInfoRecord;
+import com.epam.datalab.backendapi.resources.dto.*;
+import com.epam.datalab.backendapi.roles.RoleType;
+import com.epam.datalab.backendapi.roles.UserRoles;
 import com.epam.datalab.backendapi.service.EndpointService;
 import com.epam.datalab.backendapi.service.ImageExploratoryService;
 import com.epam.datalab.backendapi.service.ProjectService;
 import com.epam.datalab.backendapi.util.RequestBuilder;
 import com.epam.datalab.constants.ServiceConsts;
+import com.epam.datalab.dto.SharedWith;
 import com.epam.datalab.dto.UserInstanceDTO;
 import com.epam.datalab.dto.UserInstanceStatus;
 import com.epam.datalab.dto.exploratory.ExploratoryStatusDTO;
+import com.epam.datalab.dto.exploratory.ImageSharingStatus;
 import com.epam.datalab.dto.exploratory.ImageStatus;
 import com.epam.datalab.exceptions.ResourceAlreadyExistException;
 import com.epam.datalab.exceptions.ResourceNotFoundException;
@@ -52,20 +54,32 @@
 import com.google.inject.Singleton;
 import com.google.inject.name.Named;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
 
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
-import static com.epam.datalab.backendapi.domain.AuditActionEnum.CREATE;
+import static com.epam.datalab.backendapi.domain.AuditActionEnum.*;
 import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.IMAGE;
 
 @Singleton
 @Slf4j
 public class ImageExploratoryServiceImpl implements ImageExploratoryService {
     private static final String IMAGE_EXISTS_MSG = "Image with name %s is already exist in project %s";
-    private static final String IMAGE_NOT_FOUND_MSG = "Image with name %s was not found for user %s";
+    private static final String IMAGE_NOT_FOUND_FOR_USER_MSG = "Image with name %s was not found for user %s";
+    private static final String IMAGE_NOT_FOUND_MSG = "Image with name %s was not found ";
+
+    private static final String SHARE_OWN_IMAGES_PAGE = "/api/image/share";
+    private static final String TERMINATE_OWN_IMAGES_PAGE = "/api/image/terminate";
+
+    private static final String CREATE_NOTEBOOK_BASED_ON_OWN_IMAGES = "/api/exploratory/createFromOwnCustomImage";
+    private static final String CREATE_NOTEBOOK_BASED_ON_SHARED_IMAGES = "/api/exploratory/createFromSharedCustomImage";
+
+    private static final String AUDIT_SHARE_IMAGE_WITH_GROUPS = "Add group(s): %s\n";
+    private static final String AUDIT_SHARE_IMAGE_WITH_USERS = "Add user(s): %s\n";
+    private static final String AUDIT_STOP_SHARE_IMAGE_WITH_GROUPS = "Remove group(s): %s\n";
+    private static final String AUDIT_STOP_SHARE_IMAGE_WITH_USERS = "Remove user(s): %s\n";
 
     @Inject
     private ExploratoryDAO exploratoryDAO;
@@ -74,6 +88,8 @@
     @Inject
     private ExploratoryLibDAO libDAO;
     @Inject
+    private UserGroupDAO userGroupDAO;
+    @Inject
     @Named(ServiceConsts.PROVISIONING_SERVICE_NAME)
     private RESTService provisioningService;
     @Inject
@@ -82,10 +98,20 @@
     private EndpointService endpointService;
     @Inject
     private ProjectService projectService;
+    @Inject
+    private UserSettingsDAO userSettingsDAO;
+
+    @Inject
+    private SecurityDAO securityDAO;
+
+    @Override
+    public boolean imageExistInProject(String imageName, String project) {
+        return imageExploratoryDao.exist(imageName, project);
+    }
 
     @Audit(action = CREATE, type = IMAGE)
     @Override
-    public String createImage(@User UserInfo user, @Project String project, @ResourceName String exploratoryName, String imageName, String imageDescription, @Info String info) {
+    public String createImage(@User UserInfo user, @Project String project, String exploratoryName, @ResourceName String imageName, String imageDescription) {
         ProjectDTO projectDTO = projectService.get(project);
         UserInstanceDTO userInstance = exploratoryDAO.fetchRunningExploratoryFields(user.getName(), project, exploratoryName);
 
@@ -100,10 +126,15 @@
                 .description(imageDescription)
                 .status(ImageStatus.CREATING)
                 .user(user.getName())
+                .sharedWith(new SharedWith())
                 .libraries(fetchExploratoryLibs(libraries))
                 .computationalLibraries(fetchComputationalLibs(libraries))
+                .clusterConfig(userInstance.getClusterConfig())
                 .dockerImage(userInstance.getImageName())
                 .exploratoryId(userInstance.getId())
+                .templateName(userInstance.getTemplateName())
+                .instanceName(userInstance.getExploratoryName())
+                .cloudProvider(userInstance.getCloudProvider())
                 .project(userInstance.getProject())
                 .endpoint(userInstance.getEndpoint())
                 .build());
@@ -113,13 +144,36 @@
                 .withProject(project)
                 .withExploratoryName(exploratoryName)
                 .withStatus(UserInstanceStatus.CREATING_IMAGE));
-
         EndpointDTO endpointDTO = endpointService.get(userInstance.getEndpoint());
         return provisioningService.post(endpointDTO.getUrl() + ExploratoryAPI.EXPLORATORY_IMAGE,
                 user.getAccessToken(),
                 requestBuilder.newExploratoryImageCreate(user, userInstance, imageName, endpointDTO, projectDTO), String.class);
     }
 
+    @Audit(action = TERMINATE, type = IMAGE)
+    @Override
+    public void terminateImage(@User UserInfo user, @Project String project, String endpoint, @ResourceName String imageName) {
+        Optional<ImageInfoRecord> image = imageExploratoryDao.getImage(user.getName(), imageName, project, endpoint);
+        if (image.isPresent()) {
+            ImageInfoRecord imageInfoRecord = image.get();
+            imageExploratoryDao.updateImageStatus(user.getName(), imageName, project, endpoint, ImageStatus.TERMINATING);
+            EndpointDTO endpointDTO = endpointService.get(endpoint);
+            ProjectDTO projectDTO = projectService.get(project);
+            UserInstanceDTO userInstance = exploratoryDAO.fetchExploratoryFields(user.getName(), project, imageInfoRecord.getInstanceName());
+
+            log.info("ExploratoryImageCreate {}", requestBuilder.newExploratoryImageCreate(user, userInstance, imageName, endpointDTO, projectDTO));
+            provisioningService.post(endpointDTO.getUrl() + ExploratoryAPI.EXPLORATORY_IMAGE_TERMINATE,
+                    user.getAccessToken(), requestBuilder.newExploratoryImageCreate(user, userInstance, imageName, endpointDTO, projectDTO)
+                    , String.class);
+        }
+
+    }
+
+    @Override
+    public void finishTerminateImage(String imageName, String projectName, String endpoint) {
+        imageExploratoryDao.updateImageStatus(imageName, projectName, endpoint, ImageStatus.TERMINATED);
+    }
+
     @Override
     public void finishImageCreate(Image image, String exploratoryName, String newNotebookIp) {
         log.debug("Returning exploratory status with name {} to RUNNING for user {}",
@@ -130,6 +184,9 @@
                 .withExploratoryName(exploratoryName)
                 .withStatus(UserInstanceStatus.RUNNING));
         imageExploratoryDao.updateImageFields(image);
+
+        log.debug("Image {}", image);
+
         if (newNotebookIp != null) {
             log.debug("Changing exploratory ip with name {} for user {} to {}", exploratoryName, image.getUser(),
                     newNotebookIp);
@@ -139,14 +196,28 @@
     }
 
     @Override
-    public List<ImageInfoRecord> getNotFailedImages(String user, String dockerImage, String project, String endpoint) {
-        return imageExploratoryDao.getImages(user, dockerImage, project, endpoint, ImageStatus.CREATED, ImageStatus.CREATING);
+    public List<ImageInfoDTO> getNotFailedImages(UserInfo user, String dockerImage, String project, String endpoint) {
+        List<ImageInfoRecord> images = new ArrayList<>();
+        if (UserRoles.checkAccess(user, RoleType.PAGE, CREATE_NOTEBOOK_BASED_ON_OWN_IMAGES, user.getRoles())) {
+            images.addAll(imageExploratoryDao.getImages(user.getName(), dockerImage, project, endpoint, ImageStatus.ACTIVE, ImageStatus.CREATING));
+        }
+        if (UserRoles.checkAccess(user, RoleType.PAGE, CREATE_NOTEBOOK_BASED_ON_SHARED_IMAGES, user.getRoles())) {
+            images.addAll(getSharedImages(user, dockerImage, project, endpoint));
+        }
+        List<ImageInfoDTO> imageInfoDTOs = images.stream().map(img -> toImageInfoDTO(img, user)).collect(Collectors.toList());
+        return removeSharedWithIfNotOwner(user,imageInfoDTOs);
     }
 
     @Override
     public ImageInfoRecord getImage(String user, String name, String project, String endpoint) {
         return imageExploratoryDao.getImage(user, name, project, endpoint).orElseThrow(() ->
-                new ResourceNotFoundException(String.format(IMAGE_NOT_FOUND_MSG, name, user)));
+                new ResourceNotFoundException(String.format(IMAGE_NOT_FOUND_FOR_USER_MSG, name, user)));
+    }
+
+    @Override
+    public ImageInfoRecord getImage(String name, String project, String endpoint) {
+        return imageExploratoryDao.getImage(name, project, endpoint).orElseThrow(() ->
+                new ResourceNotFoundException(String.format(IMAGE_NOT_FOUND_MSG, name)));
     }
 
     @Override
@@ -154,6 +225,161 @@
         return imageExploratoryDao.getImagesForProject(project);
     }
 
+    @Override
+    public ImagesPageInfo getImagesOfUser(UserInfo user, ImageFilter imageFilter) {
+        log.debug("Loading list of images for user {}", user.getName());
+        List<ImageInfoRecord> images = imageExploratoryDao.getImagesOfUser(user.getName());
+
+        List<ImageInfoDTO> imagesDTOs = images.stream().map(img -> toImageInfoDTO(img, user)).collect(Collectors.toList());
+        imagesDTOs.addAll(getSharedImages(user).stream().map(img -> toImageInfoDTO(img, user)).collect(Collectors.toList()));
+        ImageFilterFormData filterData = getDataForFilter(imagesDTOs);
+
+        if (imageFilter == null) {
+            if (userSettingsDAO.getImageFilter(user.getName()).isPresent()) {
+                imageFilter = userSettingsDAO.getImageFilter(user.getName()).get();
+                imagesDTOs = filterImages(imagesDTOs, imageFilter);
+            } else {
+                imageFilter = new ImageFilter();
+                userSettingsDAO.setUserImageFilter(user.getName(), imageFilter);
+            }
+        } else {
+            imagesDTOs = filterImages(imagesDTOs, imageFilter);
+            userSettingsDAO.setUserImageFilter(user.getName(), imageFilter);
+        }
+
+        // do not show sharing if not owner
+        final List<ImageInfoDTO> finalImages = removeSharedWithIfNotOwner(user, imagesDTOs);
+        List<ProjectImagesInfo> projectImagesInfoList = projectService.getUserProjects(user, Boolean.FALSE)
+                .stream()
+                .map(p -> {
+                    List<ImageInfoDTO> im = finalImages.stream().filter(img -> img.getProject().equals(p.getName())).collect(Collectors.toList());
+                    return ProjectImagesInfo.builder()
+                            .project(p.getName())
+                            .images(im)
+                            .build();
+                })
+                .collect(Collectors.toList());
+        return ImagesPageInfo.builder()
+                .projectImagesInfos(projectImagesInfoList)
+                .filterData(filterData)
+                .imageFilter(imageFilter)
+                .build();
+    }
+
+    @Override
+    public void updateImageSharing(UserInfo user, ImageShareDTO imageShareDTO){
+        String info = updateImageSharingAudit(imageShareDTO);
+        shareImage(user, imageShareDTO.getImageName(), imageShareDTO.getProjectName(), imageShareDTO.getEndpoint(), imageShareDTO.getSharedWith(), info);
+    }
+
+    @Override
+    public SharingInfo getSharingInfo(String userName, String imageName, String project, String endpoint) {
+        SharingInfo sharingInfo = new SharingInfo();
+        sharingInfo.setSharedWith(getImageSharingInfo(userName, imageName, project, endpoint));
+        sharingInfo.setCanBeSharedWith(getUsersAndGroupsForSharing(userName, imageName, project, endpoint, ""));
+        return sharingInfo;
+    }
+
+    @Override
+    public List<ImageInfoRecord> getSharedImages(UserInfo userInfo) {
+        return imageExploratoryDao.getAllImages().stream()
+                .filter(img -> !img.getUser().equals(userInfo.getName()))
+                .filter(img -> hasAccess(userInfo.getName(), img.getSharedWith()))
+                .collect(Collectors.toList());
+    }
+
+    @Override
+    public List<ImageInfoRecord> getSharedImages(UserInfo userInfo, String dockerImage, String project, String endpoint) {
+        List<ImageInfoRecord> sharedImages = imageExploratoryDao.getAllImages().stream()
+                .filter(img -> img.getStatus().equals(ImageStatus.ACTIVE))
+                .filter(img -> !img.getUser().equals(userInfo.getName()))
+                .filter(img -> img.getDockerImage().equals(dockerImage) && img.getProject().equals(project) && img.getEndpoint().equals(endpoint))
+                .filter(img -> hasAccess(userInfo.getName(), img.getSharedWith()))
+                .collect(Collectors.toList());
+        log.info("Found shared with user {} images {}", userInfo.getName(), sharedImages);
+        return sharedImages;
+    }
+
+    @Override
+    public ImageUserPermissions getUserImagePermissions(UserInfo userInfo, ImageInfoRecord image) {
+        boolean canShare = image.getStatus().equals(ImageStatus.ACTIVE) && image.getUser().equals(userInfo.getName())
+                && UserRoles.checkAccess(userInfo, RoleType.PAGE, SHARE_OWN_IMAGES_PAGE, userInfo.getRoles());
+        boolean canTerminate = (image.getStatus().equals(ImageStatus.ACTIVE) || image.getStatus().equals(ImageStatus.FAILED)) &&
+                (image.getUser().equals(userInfo.getName())
+                        && UserRoles.checkAccess(userInfo, RoleType.PAGE, TERMINATE_OWN_IMAGES_PAGE, userInfo.getRoles()));
+        return new ImageUserPermissions(canShare, canTerminate);
+    }
+
+    @Override
+    public boolean canCreateFromImage(UserInfo userInfo, String imageName, String project, String endpoint) {
+        ImageInfoRecord image = getImage(imageName, project, endpoint);
+        if (image.getUser().equals(userInfo.getName())) {
+            return UserRoles.checkAccess(userInfo, RoleType.PAGE, CREATE_NOTEBOOK_BASED_ON_OWN_IMAGES, userInfo.getRoles());
+        } else {
+            return hasAccess(userInfo.getName(), image.getSharedWith())
+                    && UserRoles.checkAccess(userInfo, RoleType.PAGE, CREATE_NOTEBOOK_BASED_ON_SHARED_IMAGES, userInfo.getRoles());
+        }
+    }
+
+    @Override
+    public Set<SharedWithDTO> getUsersAndGroupsForSharing(String userName, String imageName, String project, String endpoint, String value) {
+        Set<SharedWithDTO> sharedWith = getImageSharingInfo(userName, imageName, project, endpoint);
+
+        // Find users in groups
+        Map<String, Set<String>> groupsAndUsers = securityDAO.getGroups();
+        final Set<String> usersInGroups = new HashSet<>();
+        groupsAndUsers.entrySet().stream().forEach(entry -> usersInGroups.addAll(entry.getValue()));
+        Set<String> usersFiltered = usersInGroups.stream()
+                .filter(name -> name.toLowerCase().contains(value.toLowerCase())).collect(Collectors.toSet());
+        // Find users who logged in
+        usersFiltered.addAll(securityDAO.getUserNames(value));
+
+        Set<SharedWithDTO> canBeSharedWith = usersFiltered.stream()
+                .map(s -> new SharedWithDTO(SharedWithDTO.Type.USER, s)).collect(Collectors.toSet());
+
+        canBeSharedWith.addAll(userGroupDAO.getGroupNames(value).stream()
+                .map(s -> new SharedWithDTO(SharedWithDTO.Type.GROUP, s)).collect(Collectors.toSet()));
+
+        canBeSharedWith.removeAll(sharedWith);
+        return new TreeSet<>(canBeSharedWith);
+    }
+
+    @Audit(action = UPDATE_SHARING, type = IMAGE)
+    public void shareImage(@User UserInfo user, @ResourceName String imageName, @Project String projectName, String endpoint,
+                            Set<SharedWithDTO> sharedWithDTOS, @Info String info) {
+        Optional<ImageInfoRecord> image = imageExploratoryDao.getImage(user.getName(), imageName, projectName, endpoint);
+        image.ifPresent(img -> {
+            log.info("image {}", img);
+            imageExploratoryDao.updateSharing(toSharedWith(sharedWithDTOS), img.getName(), img.getProject(), img.getEndpoint());
+        });
+    }
+
+    private boolean hasAccess(String userName, SharedWith sharedWith) {
+        boolean accessByUserName = sharedWith.getUsers().contains(userName);
+        boolean accessByGroup = sharedWith.getGroups().stream().anyMatch(groupName -> userGroupDAO.getUsers(groupName).contains(userName));
+        return accessByUserName || accessByGroup;
+    }
+
+    private Set<SharedWithDTO> toSharedWithDTOs(SharedWith sharedWith) {
+        Set<SharedWithDTO> sharedWithDTO = sharedWith.getGroups().stream()
+                .map(s -> new SharedWithDTO(SharedWithDTO.Type.GROUP, s)).collect(Collectors.toSet());
+        Set<SharedWithDTO> users = sharedWith.getUsers().stream()
+                .map(s -> new SharedWithDTO(SharedWithDTO.Type.USER, s)).collect(Collectors.toSet());
+        sharedWithDTO.addAll(users);
+        return sharedWithDTO;
+
+    }
+
+    private SharedWith toSharedWith(Set<SharedWithDTO> dtos) {
+        SharedWith sharedWith = new SharedWith();
+        dtos.forEach(dto -> {
+            if (dto.getType().equals(SharedWithDTO.Type.GROUP)) {
+                sharedWith.getGroups().add(dto.getValue());
+            } else sharedWith.getUsers().add(dto.getValue());
+        });
+        return sharedWith;
+    }
+
     private Map<String, List<Library>> fetchComputationalLibs(List<Library> libraries) {
         return libraries.stream()
                 .filter(resourceTypePredicate(ResourceType.COMPUTATIONAL))
@@ -174,4 +400,109 @@
     private Predicate<Library> resourceTypePredicate(ResourceType resourceType) {
         return l -> resourceType == l.getType();
     }
+
+    private Set<SharedWithDTO> getImageSharingInfo(String userName, String imageName, String project, String endpoint) {
+        Optional<ImageInfoRecord> image = imageExploratoryDao.getImage(userName, imageName, project, endpoint);
+        if (image.isPresent()) {
+            return toSharedWithDTOs(image.get().getSharedWith());
+        } else {
+            throw new ResourceNotFoundException(IMAGE_NOT_FOUND_FOR_USER_MSG);
+        }
+    }
+
+    private ImageSharingStatus getImageSharingStatus(String username, ImageInfoRecord image) {
+        boolean notShared = image.getSharedWith().getUsers().isEmpty() && image.getSharedWith().getGroups().isEmpty();
+        if (notShared && image.getUser().equals(username)) {
+            return ImageSharingStatus.PRIVATE;
+        } else if (!notShared && image.getUser().equals(username)) {
+            return ImageSharingStatus.SHARED;
+        }
+        return ImageSharingStatus.RECEIVED;
+    }
+
+    private List<ImageInfoDTO> removeSharedWithIfNotOwner(UserInfo user, List<ImageInfoDTO> imageInfoDTOS){
+        imageInfoDTOS.forEach(img -> {
+            if(!img.getUser().equals(user.getName())){
+                img.setSharedWith(new SharedWith());
+            }
+        });
+        return imageInfoDTOS;
+    }
+
+    private List<ImageInfoDTO> filterImages(List<ImageInfoDTO> images, ImageFilter filter) {
+        return images.stream()
+                .filter(img -> img.getName().toLowerCase().contains(filter.getImageName().toLowerCase()))
+                .filter(img -> CollectionUtils.isEmpty(filter.getStatuses()) || filter.getStatuses().contains(img.getStatus()))
+                .filter(img -> CollectionUtils.isEmpty(filter.getEndpoints()) || filter.getEndpoints().contains(img.getEndpoint()))
+                .filter(img -> CollectionUtils.isEmpty(filter.getTemplateNames()) || filter.getTemplateNames().contains(img.getTemplateName()))
+                .filter(img -> CollectionUtils.isEmpty(filter.getSharingStatuses()) || filter.getSharingStatuses().contains(img.getSharingStatus()))
+                .collect(Collectors.toList());
+
+    }
+
+    private ImageFilterFormData getDataForFilter(List<ImageInfoDTO> images) {
+        ImageFilterFormData filterData = new ImageFilterFormData();
+        filterData.setImageNames(images.stream().map(ImageInfoDTO::getName).collect(Collectors.toSet()));
+        filterData.setStatuses(images.stream().map(ImageInfoDTO::getStatus).collect(Collectors.toSet()));
+        filterData.setEndpoints(images.stream().map(ImageInfoDTO::getEndpoint).collect(Collectors.toSet()));
+        filterData.setTemplateNames(images.stream().map(ImageInfoDTO::getTemplateName).collect(Collectors.toSet()));
+        filterData.setSharingStatuses(images.stream().map(ImageInfoDTO::getSharingStatus).collect(Collectors.toSet()));
+        return filterData;
+    }
+
+    private String updateImageSharingAudit(ImageShareDTO imageShareDTO){
+        StringBuilder audit = new StringBuilder();
+        imageExploratoryDao.getImage(imageShareDTO.getImageName(), imageShareDTO.getProjectName(), imageShareDTO.getEndpoint()).ifPresent((img)->{
+            Set<String> oldGroups = new TreeSet<>(img.getSharedWith().getGroups());
+            Set<String> oldUsers = new TreeSet<>(img.getSharedWith().getUsers());
+            SharedWith oldSharedWith = img.getSharedWith();
+            SharedWith newSharedWith = toSharedWith(imageShareDTO.getSharedWith());
+
+            oldSharedWith.getGroups().removeAll(newSharedWith.getGroups());
+            oldSharedWith.getUsers().removeAll(newSharedWith.getUsers());
+
+            newSharedWith.getGroups().removeAll(oldGroups);
+            newSharedWith.getUsers().removeAll(oldUsers);
+
+            if(!oldSharedWith.getGroups().isEmpty()){
+                audit.append(String.format(AUDIT_STOP_SHARE_IMAGE_WITH_GROUPS, String.join(", ", oldSharedWith.getGroups())));
+            }
+            if(!oldSharedWith.getUsers().isEmpty()){
+                audit.append(String.format(AUDIT_STOP_SHARE_IMAGE_WITH_USERS, String.join(", ", oldSharedWith.getUsers())));
+            }
+            if(!newSharedWith.getGroups().isEmpty()){
+                audit.append(String.format(AUDIT_SHARE_IMAGE_WITH_GROUPS, String.join(", ", newSharedWith.getGroups())));
+            }
+            if(!newSharedWith.getUsers().isEmpty()){
+                audit.append(String.format(AUDIT_SHARE_IMAGE_WITH_USERS, String.join(", ", newSharedWith.getUsers())));
+            }
+
+        });
+        return audit.toString();
+    }
+
+    private ImageInfoDTO toImageInfoDTO(ImageInfoRecord imageInfoRecord, UserInfo userInfo){
+        return ImageInfoDTO.builder()
+                .name(imageInfoRecord.getName())
+                .timestamp(imageInfoRecord.getTimestamp())
+                .description(imageInfoRecord.getDescription())
+                .project(imageInfoRecord.getProject())
+                .endpoint(imageInfoRecord.getEndpoint())
+                .user(imageInfoRecord.getUser())
+                .application(imageInfoRecord.getApplication())
+                .templateName(imageInfoRecord.getTemplateName())
+                .instanceName(imageInfoRecord.getInstanceName())
+                .cloudProvider(imageInfoRecord.getCloudProvider())
+                .dockerImage(imageInfoRecord.getDockerImage())
+                .fullName(imageInfoRecord.getFullName())
+                .status(imageInfoRecord.getStatus())
+                .sharingStatus(getImageSharingStatus(userInfo.getName(), imageInfoRecord))
+                .imageUserPermissions(getUserImagePermissions(userInfo, imageInfoRecord))
+                .sharedWith(imageInfoRecord.getSharedWith())
+                .clusterConfig(imageInfoRecord.getClusterConfig())
+                .exploratoryURL(imageInfoRecord.getExploratoryURL())
+                .libraries(imageInfoRecord.getLibraries())
+                .computationalLibraries(imageInfoRecord.getComputationalLibraries())
+        .build();
+    }
 }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/InfrastructureInfoServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/InfrastructureInfoServiceImpl.java
index 2aca621..069a669 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/InfrastructureInfoServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/InfrastructureInfoServiceImpl.java
@@ -60,6 +60,11 @@
     private static final String PERMISSION_UPLOAD = "/api/bucket/upload";
     private static final String PERMISSION_DOWNLOAD = "/api/bucket/download";
     private static final String PERMISSION_DELETE = "/api/bucket/delete";
+
+    private static final String CONNECTED_PLATFORMS_PERMISSION_VIEW = "/api/connected_platforms/view";
+    private static final String CONNECTED_PLATFORMS_PERMISSION_ADD = "/api/connected_platforms/add";
+    private static final String CONNECTED_PLATFORMS_PERMISSION_DISCONNECT = "/api/connected_platforms/disconnect";
+
     private static final String INFRASTRUCTURE_STATUS = "infrastructure/status";
 
     private final ExploratoryDAO expDAO;
@@ -124,6 +129,11 @@
                         .download(checkAccess(userInfo, PERMISSION_DOWNLOAD))
                         .delete(checkAccess(userInfo, PERMISSION_DELETE))
                         .build())
+                .connectedPlatforms(HealthStatusPageDTO.ConnectedPlatforms.builder()
+                        .view(checkAccess(userInfo, CONNECTED_PLATFORMS_PERMISSION_VIEW))
+                        .add(checkAccess(userInfo, CONNECTED_PLATFORMS_PERMISSION_ADD))
+                        .disconnect(checkAccess(userInfo, CONNECTED_PLATFORMS_PERMISSION_DISCONNECT))
+                .build())
                 .build();
     }
 
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/InfrastructureTemplateServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/InfrastructureTemplateServiceImpl.java
index da13cf1..fd609d1 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/InfrastructureTemplateServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/InfrastructureTemplateServiceImpl.java
@@ -28,6 +28,7 @@
 import com.epam.datalab.backendapi.domain.EndpointDTO;
 import com.epam.datalab.backendapi.resources.dto.SparkStandaloneConfiguration;
 import com.epam.datalab.backendapi.resources.dto.aws.AwsEmrConfiguration;
+import com.epam.datalab.backendapi.resources.dto.azure.AzureHDInsightConfiguration;
 import com.epam.datalab.backendapi.resources.dto.gcp.GcpDataprocConfiguration;
 import com.epam.datalab.backendapi.roles.RoleType;
 import com.epam.datalab.backendapi.roles.UserRoles;
@@ -141,8 +142,11 @@
                                 .minDataprocPreemptibleInstanceCount(configuration.getMinDataprocPreemptibleCount())
                                 .build());
             case AZURE:
-                log.error("Dataengine service is not supported currently for {}", AZURE);
-                throw new UnsupportedOperationException("Dataengine service is not supported currently for " + AZURE);
+                return new AzureFullComputationalTemplate(metadataDTO,
+                        AzureHDInsightConfiguration.builder()
+                                .minHdinsightInstanceCount(configuration.getMinHDInsightInstanceCount())
+                                .maxHdinsightInstanceCount(configuration.getMaxHDInsightInstanceCount())
+                                .build());
             default:
                 throw new UnsupportedOperationException("Dataengine service is not supported currently for " + cloudProvider);
         }
@@ -250,6 +254,17 @@
         }
     }
 
+    private static class AzureFullComputationalTemplate extends FullComputationalTemplate {
+        @JsonProperty("limits")
+        private AzureHDInsightConfiguration azureHDInsightConfiguration;
+
+        AzureFullComputationalTemplate(ComputationalMetadataDTO metadataDTO,
+                                       AzureHDInsightConfiguration azureHDInsightConfiguration){
+            super(metadataDTO);
+            this.azureHDInsightConfiguration = azureHDInsightConfiguration;
+        }
+    }
+
     private static class GcpFullComputationalTemplate extends FullComputationalTemplate {
         @JsonProperty("limits")
         private GcpDataprocConfiguration gcpDataprocConfiguration;
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/LibraryServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/LibraryServiceImpl.java
index cfc5e6c..cf64084 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/LibraryServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/LibraryServiceImpl.java
@@ -60,7 +60,7 @@
 
 import static com.epam.datalab.backendapi.domain.AuditActionEnum.INSTALL_LIBS;
 import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.COMPUTE;
-import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.NOTEBOOK;
+import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.INSTANCE;
 import static com.epam.datalab.backendapi.domain.NotebookTemplate.*;
 import static com.epam.datalab.dto.LibraryGroups.*;
 
@@ -142,7 +142,7 @@
         return uuid;
     }
 
-    @Audit(action = INSTALL_LIBS, type = NOTEBOOK)
+    @Audit(action = INSTALL_LIBS, type = INSTANCE)
     @Override
     public String installExploratoryLibs(@User UserInfo ui, @Project String project, @ResourceName String expName, List<LibInstallDTO> libs, @Info String auditInfo) {
         final UserInstanceDTO userInstance = exploratoryDAO.fetchRunningExploratoryFields(ui.getName(), project, expName);
@@ -163,10 +163,12 @@
         if (isTemplateGroup(templateName, Stream.of(JUPYTER, ZEPPELIN))) {
             groups.addAll(Arrays.asList(GROUP_R_PKG, GROUP_JAVA));
         }
-        if (isTemplateGroup(templateName, Stream.of(DEEP_LEARNING, TENSOR, TENSOR_GCP,
-                DEEP_LEARNING_GCP, DEEP_LEARNING_AWS, DEEP_LEARNING_AZURE))) {
+
+        if (isTemplateGroup(templateName, Stream.of(DEEP_LEARNING, TENSOR, TENSOR_GCP, TENSOR_JUPYTERLAB,
+                DEEP_LEARNING_GCP, DEEP_LEARNING_AWS, DEEP_LEARNING_AZURE, JUPYTER_GPU))) {
             groups.add(GROUP_JAVA);
         }
+      
         if (isTemplateGroup(templateName, Stream.of(RSTUDIO, TENSOR_RSTUDIO))) {
             groups.add(GROUP_R_PKG);
         }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ProjectServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ProjectServiceImpl.java
index f5bb227..c910ed9 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ProjectServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/ProjectServiceImpl.java
@@ -124,7 +124,8 @@
     public List<ProjectDTO> getProjectsByEndpoint(String endpointName) {
         return projectDAO.getProjectsByEndpoint(endpointName);
     }
-
+    
+    @BudgetLimited
     @Override
     public void create(UserInfo user, ProjectDTO projectDTO, String projectName) {
         if (!projectDAO.get(projectDTO.getName()).isPresent()) {
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/SchedulerJobServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/SchedulerJobServiceImpl.java
index 546a044..e1caab9 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/SchedulerJobServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/SchedulerJobServiceImpl.java
@@ -65,7 +65,7 @@
 
 import static com.epam.datalab.backendapi.domain.AuditActionEnum.SET_UP_SCHEDULER;
 import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.COMPUTE;
-import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.NOTEBOOK;
+import static com.epam.datalab.backendapi.domain.AuditResourceTypeEnum.INSTANCE;
 import static com.epam.datalab.constants.ServiceConsts.PROVISIONING_SERVICE_NAME;
 import static com.epam.datalab.dto.UserInstanceStatus.CONFIGURING;
 import static com.epam.datalab.dto.UserInstanceStatus.CREATING;
@@ -129,7 +129,7 @@
                         exploratoryName) + " with computational resource " + computationalName));
     }
 
-    @Audit(action = SET_UP_SCHEDULER, type = NOTEBOOK)
+    @Audit(action = SET_UP_SCHEDULER, type = INSTANCE)
     @Override
     public void updateExploratorySchedulerData(@User UserInfo user, @Project String project, @ResourceName String exploratoryName, SchedulerJobDTO dto) {
         validateExploratoryStatus(user.getName(), project, exploratoryName);
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/util/AuditUtils.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/util/AuditUtils.java
new file mode 100644
index 0000000..2de4de6
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/util/AuditUtils.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.epam.datalab.backendapi.util;
+
+import com.epam.datalab.backendapi.domain.AuditReportLine;
+import jersey.repackaged.com.google.common.collect.Lists;
+import org.apache.commons.lang3.StringUtils;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.time.format.FormatStyle;
+import java.util.*;
+
+/**
+ * Class helper to handle the audit records
+ */
+public class AuditUtils {
+
+    private static final String REPORT_FIRST_LINE = "Available reporting period from: %s to: %s";
+    private static final String[] AUDIT_REPORT_HEADER = {"Date", "User", "Action", "Project", "Resource type", "Resource"};
+
+    /**
+     * @param from   formatted date, like 2020-04-07
+     * @param to     formatted date, like 2020-05-07
+     * @param locale user's locale
+     * @return line, like:
+     * Available reporting period from: 2020-04-07 to: 2020-04-07"
+     */
+    public static String getFirstLine(LocalDate from, LocalDate to, String locale) {
+        return CSVFormatter.formatLine(Lists.newArrayList(String.format(REPORT_FIRST_LINE,
+                        Optional.ofNullable(from).map(date -> date.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.forLanguageTag(locale)))).orElse(StringUtils.EMPTY),
+                        Optional.ofNullable(to).map(date -> date.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM).withLocale(Locale.forLanguageTag(locale)))).orElse(StringUtils.EMPTY))),
+                CSVFormatter.SEPARATOR, '\"');
+    }
+
+    /**
+     *
+     * @param line - Audit Report line objet, which contains exported rows
+     * @return formatted string of the Audit reportL
+     * Date,User,Action,Project,Resource type,Resource
+     * 2022-03-20,test,LOG_IN,,,
+     * 2022-03-20,test,LOG_IN,,,
+     * 2022-03-19,test,LOG_IN,,,
+     * 2022-03-17,test,LOG_IN,,,
+     */
+    public static String printLine(AuditReportLine line) {
+        List<String> lines = new ArrayList<>();
+        lines.add(getOrEmpty(line.getTimestamp().toString()));
+        lines.add(getOrEmpty(line.getUser()));
+        lines.add(getOrEmpty(line.getAction()));
+        lines.add(getOrEmpty(line.getProject()));
+        lines.add(getOrEmpty(line.getResourceType()));;
+        lines.add(getOrEmpty(line.getResourceName()));
+        return CSVFormatter.formatLine(lines, CSVFormatter.SEPARATOR);
+    }
+
+    public static String getHeader() {
+        return CSVFormatter.formatLine(Arrays.asList(AuditUtils.AUDIT_REPORT_HEADER), CSVFormatter.SEPARATOR);
+    }
+
+    private static String getOrEmpty(String s) {
+        return Objects.nonNull(s) ? s : StringUtils.EMPTY;
+    }
+}
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/util/BillingUtils.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/util/BillingUtils.java
index fe9575f..93f887b 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/util/BillingUtils.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/util/BillingUtils.java
@@ -39,7 +39,7 @@
 
 @Slf4j
 public class BillingUtils {
-    private static final String[] AVAILABLE_NOTEBOOKS = {"zeppelin", "tensor-rstudio", "rstudio", "tensor", "superset", "jupyterlab", "jupyter", "deeplearning"};
+    private static final String[] AVAILABLE_NOTEBOOKS = {"zeppelin", "tensor-rstudio", "tensor-jupyterlab", "rstudio", "tensor", "superset", "jupyterlab", "jupyter", "jupyter-gpu", "deeplearning"};
     private static final String[] BILLING_FILTERED_REPORT_HEADERS = {"DataLab ID", "Project", "DataLab Resource Type", "Status", "Shape", "Product", "Cost"};
     private static final String[] COMPLETE_REPORT_REPORT_HEADERS = {"DataLab ID", "User", "Project", "DataLab Resource Type", "Status", "Shape", "Product", "Cost"};
 
@@ -51,6 +51,7 @@
     private static final String EDGE_VOLUME_FORMAT = "%s-%s-%s-edge-volume-primary";
     private static final String PROJECT_ENDPOINT_BUCKET_FORMAT = "%s-%s-%s-bucket";
     private static final String ENDPOINT_SHARED_BUCKET_FORMAT = "%s-%s-shared-bucket";
+    private static final String DATA_ENGINE_BUCKET_FORMAT = "%s-bucket";
 
     private static final String VOLUME_PRIMARY_FORMAT = "%s-volume-primary";
     private static final String VOLUME_PRIMARY_COMPUTATIONAL_FORMAT = "%s-%s-volume-primary";
@@ -60,6 +61,11 @@
     private static final String IMAGE_STANDARD_FORMAT1 = "%s-%s-%s-%s-notebook-image";
     private static final String IMAGE_STANDARD_FORMAT2 = "%s-%s-%s-notebook-image";
     private static final String IMAGE_CUSTOM_FORMAT = "%s-%s-%s-%s-%s";
+    // GCP specific
+    private static final String IMAGE_VOLUME_PRIMARY_GCP = "%s-%s-%s-%s-primary-image";
+    private static final String IMAGE_VOLUME_SECONDARY_GCP = "%s-%s-%s-%s-secondary-image";
+    private static final String IMAGE_CUSTOM_VOLUME_PRIMARY_GCP = "%s-%s-%s-%s-primary-image-%s";
+    private static final String IMAGE_CUSTOM_VOLUME_SECONDARY_GCP = "%s-%s-%s-%s-secondary-image-%s";
 
     private static final String SHARED_RESOURCE = "Shared resource";
     private static final String IMAGE_NAME = "Image";
@@ -145,7 +151,7 @@
                 .stream()
                 .filter(cr -> cr.getComputationalId() != null)
                 .flatMap(cr -> {
-                    final String computationalId = cr.getComputationalId().toLowerCase();
+                    final String computationalId = getDatalabIdForComputeResources(cr);
                     return Stream.concat(Stream.of(
                             withUserProjectEndpoint(userInstance)
                                     .resourceName(cr.getComputationalName())
@@ -173,6 +179,11 @@
                                     .resourceName(cr.getComputationalName())
                                     .datalabId(String.format(VOLUME_SECONDARY_COMPUTATIONAL_FORMAT, computationalId, "m"))
                                     .resourceType(VOLUME)
+                                    .build(),
+                            withUserProjectEndpoint(userInstance)
+                                    .resourceName(cr.getComputationalName())
+                                    .datalabId(String.format(DATA_ENGINE_BUCKET_FORMAT, computationalId))
+                                    .resourceType(BUCKET)
                                     .build()
                             ),
                             getSlaveVolumes(userInstance, cr, maxSparkInstanceCount)
@@ -206,17 +217,33 @@
 
     public static Stream<BillingReportLine> customImageBillingDataStream(ImageInfoRecord image, String sbn) {
         String imageId = String.format(IMAGE_CUSTOM_FORMAT, sbn, image.getProject(), image.getEndpoint(), image.getApplication(), image.getName()).toLowerCase();
+        String imageIdGCP1 = String.format(IMAGE_CUSTOM_VOLUME_PRIMARY_GCP, sbn, image.getProject(), image.getEndpoint(), image.getApplication(), image.getName()).toLowerCase();
+        String imageIdGCP2 = String.format(IMAGE_CUSTOM_VOLUME_SECONDARY_GCP, sbn, image.getProject(), image.getEndpoint(), image.getApplication(), image.getName()).toLowerCase();
         return Stream.of(
-                BillingReportLine.builder().resourceName(image.getName()).project(image.getProject()).datalabId(imageId).user(image.getUser()).resourceType(IMAGE).build()
+                BillingReportLine.builder().resourceName(image.getName()).project(image.getProject()).datalabId(imageId).user(image.getUser()).resourceType(IMAGE).build(),
+                BillingReportLine.builder().resourceName(image.getName()).project(image.getProject()).datalabId(imageIdGCP1).user(image.getUser()).resourceType(IMAGE).build(),
+                BillingReportLine.builder().resourceName(image.getName()).project(image.getProject()).datalabId(imageIdGCP2).user(image.getUser()).resourceType(IMAGE).build()
+
         );
     }
 
+    /**
+        For HDInsight computational_id begins with random id
+        which differs from datalab_id tag
+     */
+    private static String getDatalabIdForComputeResources(UserComputationalResource cr){
+        if(cr.getTemplateName().equals("HDInsight cluster")){
+            return cr.getComputationalId().toLowerCase().substring(7);
+        }
+        return cr.getComputationalId().toLowerCase();
+    }
+
     private static Stream<BillingReportLine> getSlaveVolumes(UserInstanceDTO userInstance, UserComputationalResource cr, Integer maxSparkInstanceCount) {
         List<BillingReportLine> list = new ArrayList<>();
         for (int i = 1; i <= maxSparkInstanceCount; i++) {
-            list.add(withUserProjectEndpoint(userInstance).resourceName(cr.getComputationalName()).datalabId(String.format(VOLUME_PRIMARY_COMPUTATIONAL_FORMAT, cr.getComputationalId().toLowerCase(), "s" + i))
+            list.add(withUserProjectEndpoint(userInstance).resourceName(cr.getComputationalName()).datalabId(String.format(VOLUME_PRIMARY_COMPUTATIONAL_FORMAT, getDatalabIdForComputeResources(cr), "s" + i))
                     .resourceType(VOLUME).build());
-            list.add(withUserProjectEndpoint(userInstance).resourceName(cr.getComputationalName()).datalabId(String.format(VOLUME_SECONDARY_COMPUTATIONAL_FORMAT, cr.getComputationalId().toLowerCase(), "s" + i))
+            list.add(withUserProjectEndpoint(userInstance).resourceName(cr.getComputationalName()).datalabId(String.format(VOLUME_SECONDARY_COMPUTATIONAL_FORMAT, getDatalabIdForComputeResources(cr), "s" + i))
                     .resourceType(VOLUME).build());
         }
         return list.stream();
@@ -260,6 +287,22 @@
                     .user(SHARED_RESOURCE)
                     .resourceType(IMAGE)
                     .build());
+            list.add(BillingReportLine
+                    .builder()
+                    .resourceName(IMAGE_NAME)
+                    .datalabId(String.format(IMAGE_VOLUME_PRIMARY_GCP, sbn, project, endpoint, notebook).toLowerCase())
+                    .project(project)
+                    .user(SHARED_RESOURCE)
+                    .resourceType(IMAGE)
+                    .build());
+            list.add(BillingReportLine
+                    .builder()
+                    .resourceName(IMAGE_NAME)
+                    .datalabId(String.format(IMAGE_VOLUME_SECONDARY_GCP, sbn, project, endpoint, notebook).toLowerCase())
+                    .project(project)
+                    .user(SHARED_RESOURCE)
+                    .resourceType(IMAGE)
+                    .build());
         }
         return list.stream();
     }
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/util/RequestBuilder.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/util/RequestBuilder.java
index 7b1ea0a..84a27c8 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/util/RequestBuilder.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/util/RequestBuilder.java
@@ -30,6 +30,7 @@
 import com.epam.datalab.backendapi.resources.dto.ComputationalCreateFormDTO;
 import com.epam.datalab.backendapi.resources.dto.SparkStandaloneClusterCreateForm;
 import com.epam.datalab.backendapi.resources.dto.aws.AwsComputationalCreateForm;
+import com.epam.datalab.backendapi.resources.dto.azure.AzureComputationalCreateForm;
 import com.epam.datalab.backendapi.resources.dto.gcp.GcpComputationalCreateForm;
 import com.epam.datalab.cloud.CloudProvider;
 import com.epam.datalab.dto.*;
@@ -40,6 +41,8 @@
 import com.epam.datalab.dto.aws.computational.SparkComputationalCreateAws;
 import com.epam.datalab.dto.aws.exploratory.ExploratoryCreateAws;
 import com.epam.datalab.dto.azure.AzureCloudSettings;
+import com.epam.datalab.dto.azure.computational.AzureComputationalTerminateDTO;
+import com.epam.datalab.dto.azure.computational.ComputationalCreateAzure;
 import com.epam.datalab.dto.azure.computational.SparkComputationalCreateAzure;
 import com.epam.datalab.dto.azure.exploratory.ExploratoryActionStartAzure;
 import com.epam.datalab.dto.azure.exploratory.ExploratoryActionStopAzure;
@@ -339,7 +342,15 @@
         CloudProvider cloudProvider = endpointDTO.getCloudProvider();
         switch (cloudProvider) {
             case AZURE:
-                throw new UnsupportedOperationException("Creating dataengine service is not supported yet");
+                AzureComputationalCreateForm azureForm = (AzureComputationalCreateForm) form;
+                computationalCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ComputationalCreateAzure.class)
+                        .withInstanceCount(azureForm.getInstanceCount())
+                        .withMasterInstanceType(azureForm.getMasterInstanceType())
+                        .withSlaveInstanceType(azureForm.getSlaveInstanceType())
+                        .withVersion(azureForm.getVersion())
+                        .withConfig((azureForm.getConfig()))
+                        .withSharedImageEnabled(String.valueOf(projectDTO.isSharedImageEnabled()));
+                break;
             case AWS:
                 AwsComputationalCreateForm awsForm = (AwsComputationalCreateForm) form;
                 computationalCreate = (T) newResourceSysBaseDTO(userInfo.getName(), cloudProvider, ComputationalCreateAws.class)
@@ -460,7 +471,11 @@
                 computationalTerminate = (T) terminateDTO;
                 break;
             case AZURE:
-                computationalTerminate = (T) newResourceSysBaseDTO(resourceCreator, cloudProvider, ComputationalTerminateDTO.class);
+                AzureComputationalTerminateDTO azureTerminateDTO =  newResourceSysBaseDTO(resourceCreator, cloudProvider, AzureComputationalTerminateDTO.class);
+                if (computationalResource.getDataEngineType() == DataEngineType.CLOUD_SERVICE){
+                    azureTerminateDTO.setClusterName(computationalResource.getComputationalId());
+                }
+                computationalTerminate = (T) azureTerminateDTO;
                 break;
             case GCP:
                 GcpComputationalTerminateDTO gcpTerminateDTO = newResourceSysBaseDTO(resourceCreator, cloudProvider,
diff --git a/services/self-service/src/main/resources/mongo/aws/mongo_roles.json b/services/self-service/src/main/resources/mongo/aws/mongo_roles.json
index 4750fae..bfce85c 100644
--- a/services/self-service/src/main/resources/mongo/aws/mongo_roles.json
+++ b/services/self-service/src/main/resources/mongo/aws/mongo_roles.json
@@ -180,6 +180,18 @@
     ]
   },
   {
+    "_id": "nbCreateTensorJupyterlab",
+    "description": "Create Notebook JupyterLab with TensorFlow",
+    "type": "NOTEBOOK",
+    "cloud": "AWS",
+    "exploratories": [
+      "docker.datalab-tensor-jupyterlab"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "nbCreateTensorRstudio",
     "description": "Create Notebook RStudio with TensorFlow",
     "type": "NOTEBOOK",
@@ -216,6 +228,18 @@
     ]
   },
   {
+    "_id": "compShapes_c4.large_fetching",
+    "description": "Use c4.large instance shape for cluster",
+    "type": "COMPUTATIONAL_SHAPE",
+    "cloud": "AWS",
+    "computational_shapes": [
+      "c4.large"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "compShapes_c4.xlarge_fetching",
     "description": "Use c4.xlarge instance shape for cluster",
     "type": "COMPUTATIONAL_SHAPE",
diff --git a/services/self-service/src/main/resources/mongo/azure/mongo_roles.json b/services/self-service/src/main/resources/mongo/azure/mongo_roles.json
index 49758fd..8717d36 100644
--- a/services/self-service/src/main/resources/mongo/azure/mongo_roles.json
+++ b/services/self-service/src/main/resources/mongo/azure/mongo_roles.json
@@ -120,6 +120,18 @@
     ]
   },
   {
+    "_id": "nbCreateJupyterLab",
+    "description": "Create Notebook JupyterLab",
+    "type": "NOTEBOOK",
+    "cloud": "AZURE",
+    "exploratories": [
+      "docker.datalab-jupyterlab"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "nbCreateRstudio",
     "description": "Create Notebook RStudio",
     "type": "NOTEBOOK",
@@ -168,6 +180,30 @@
     ]
   },
   {
+    "_id": "nbCreateDataEngineService",
+    "description": "Create Data Engine Service",
+    "type": "COMPUTATIONAL",
+    "cloud": "AZURE",
+    "computationals": [
+      "docker.datalab-dataengine-service"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
+    "_id": "compShapes_Standard_D12_v2_fetching",
+    "description": "Use Standard_D12_v2 instance shape for cluster",
+    "type": "COMPUTATIONAL_SHAPE",
+    "cloud": "AZURE",
+    "computational_shapes": [
+      "Standard_D12_v2"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "compShapes_Standard_F4s_fetching",
     "description": "Use Standard_F4s instance shape for cluster",
     "type": "COMPUTATIONAL_SHAPE",
@@ -180,6 +216,18 @@
     ]
   },
   {
+    "_id": "compShapes_Standard_E4_v3_fetching",
+    "description": "Use Standard_E4_v3 instance shape for cluster",
+    "type": "COMPUTATIONAL_SHAPE",
+    "cloud": "AZURE",
+    "computational_shapes": [
+      "Standard_E4_v3"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "compShapes_Standard_E4s_v3_fetching",
     "description": "Use Standard_E4s_v3 instance shape for cluster",
     "type": "COMPUTATIONAL_SHAPE",
@@ -192,6 +240,18 @@
     ]
   },
   {
+    "_id": "compShapes_Standard_E16_v3_fetching",
+    "description": "Use Standard_E16_v3 instance shape for cluster",
+    "type": "COMPUTATIONAL_SHAPE",
+    "cloud": "AZURE",
+    "computational_shapes": [
+      "Standard_E16_v3"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "compShapes_Standard_E16s_v3_fetching",
     "description": "Use Standard_E16s_v3 instance shape for cluster",
     "type": "COMPUTATIONAL_SHAPE",
@@ -204,6 +264,18 @@
     ]
   },
   {
+    "_id": "compShapes_Standard_E32_v3_fetching",
+    "description": "Use Standard_E32_v3 instance shape for cluster",
+    "type": "COMPUTATIONAL_SHAPE",
+    "cloud": "AZURE",
+    "computational_shapes": [
+      "Standard_E32_v3"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "compShapes_Standard_E32s_v3_fetching",
     "description": "Use Standard_E32s_v3 instance shape for cluster",
     "type": "COMPUTATIONAL_SHAPE",
diff --git a/services/self-service/src/main/resources/mongo/gcp/mongo_roles.json b/services/self-service/src/main/resources/mongo/gcp/mongo_roles.json
index e75c29c..a914f34 100644
--- a/services/self-service/src/main/resources/mongo/gcp/mongo_roles.json
+++ b/services/self-service/src/main/resources/mongo/gcp/mongo_roles.json
@@ -1,5 +1,17 @@
 [
   {
+    "_id": "nbShapes_a2-highgpu-1g_fetching",
+    "description": "Use a2-highgpu-1g instance shape for notebook",
+    "type": "NOTEBOOK_SHAPE",
+    "cloud": "GCP",
+    "exploratory_shapes": [
+      "a2-highgpu-1g"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "nbShapes_n1-highcpu-2_fetching",
     "description": "Use n1-highcpu-2 instance shape for notebook",
     "type": "NOTEBOOK_SHAPE",
@@ -108,6 +120,18 @@
     ]
   },
   {
+    "_id": "nbCreateJupyterGpu",
+    "description": "Create Notebook Jupyter Gpu",
+    "type": "NOTEBOOK",
+    "cloud": "GCP",
+    "exploratories": [
+      "docker.datalab-jupyter-gpu"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "nbCreateJupyterLab",
     "description": "Create Notebook JupyterLab",
     "type": "NOTEBOOK",
@@ -286,5 +310,17 @@
     "groups": [
       "$anyuser"
     ]
+  },
+  {
+    "_id": "compShapes_a2-highgpu-1g_fetching",
+    "description": "Use a2-highgpu-1g instance shape for cluster",
+    "type": "COMPUTATIONAL_SHAPE",
+    "cloud": "GCP",
+    "computational_shapes": [
+      "a2-highgpu-1g"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
   }
 ]
diff --git a/services/self-service/src/main/resources/mongo/general/mongo_roles.json b/services/self-service/src/main/resources/mongo/general/mongo_roles.json
index 5ce782b..c3cfefe 100644
--- a/services/self-service/src/main/resources/mongo/general/mongo_roles.json
+++ b/services/self-service/src/main/resources/mongo/general/mongo_roles.json
@@ -1,5 +1,53 @@
 [
   {
+    "_id": "imgShareOwnImages",
+    "description": "Allow to share own images",
+    "type": "IMAGE",
+    "cloud": "GENERAL",
+    "pages": [
+      "/api/image/share"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
+    "_id": "imgTerminateOwnImages",
+    "description": "Allow to terminate own images",
+    "type": "IMAGE",
+    "cloud": "GENERAL",
+    "pages": [
+      "/api/image/terminate"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
+    "_id": "nbCreateBasedOnCustomOwnImages",
+    "description": "Create Notebook based on custom own images",
+    "type": "NOTEBOOK",
+    "cloud": "GENERAL",
+    "pages": [
+      "/api/exploratory/createFromOwnCustomImage"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
+    "_id": "nbCreateBasedOnSharedImages",
+    "description": "Create Notebook based on custom shared images",
+    "type": "NOTEBOOK",
+    "cloud": "GENERAL",
+    "pages": [
+      "/api/exploratory/createFromSharedCustomImage"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "nbBillingReportFull",
     "description": "View full billing report for all users",
     "type": "BILLING",
@@ -48,6 +96,42 @@
     ]
   },
   {
+    "_id": "connectedPlatformsView",
+    "description": "Allow to view connected platforms",
+    "type": "CONNECTED_PLATFORMS",
+    "cloud": "GENERAL",
+    "pages": [
+      "/api/connected_platforms/view"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
+    "_id": "connectedPlatformsDisconnect",
+    "description": "Allow to disconnect connected platforms",
+    "type": "CONNECTED_PLATFORMS",
+    "cloud": "GENERAL",
+    "pages": [
+      "/api/connected_platforms/disconnect"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
+    "_id": "connectedPlatformsAdd",
+    "description": "Allow to add connected platforms",
+    "type": "CONNECTED_PLATFORMS",
+    "cloud": "GENERAL",
+    "pages": [
+      "/api/connected_platforms/add"
+    ],
+    "groups": [
+      "$anyuser"
+    ]
+  },
+  {
     "_id": "bucketBrowserDelete",
     "description": "Allow to delete object via bucket browser",
     "type": "BUCKET_BROWSER",
diff --git a/services/self-service/src/main/resources/webapp/angular.json b/services/self-service/src/main/resources/webapp/angular.json
index 8dd6228..cc3beda 100644
--- a/services/self-service/src/main/resources/webapp/angular.json
+++ b/services/self-service/src/main/resources/webapp/angular.json
@@ -11,7 +11,12 @@
         "build": {
           "builder": "@angular-devkit/build-angular:browser",
           "options": {
-            "allowedCommonJsDependencies": ["chart.js", "ng-daterangepicker", "moment-timezone"],
+            "allowedCommonJsDependencies": [
+              "chart.js",
+              "ng-daterangepicker",
+              "moment-timezone",
+              "rxjs-compat"
+            ],
             "aot": true,
             "outputPath": "dist",
             "index": "src/index.html",
@@ -23,8 +28,10 @@
               "src/assets",
               "src/favicon.ico"
             ],
-            "styles": [{
-                "input": "node_modules/@angular/material/prebuilt-themes/deeppurple-amber.css"
+            "styles": [
+              {
+                "input": "node_modules/@angular/material/prebuilt-themes/deeppurple-amber.css",
+                "inject": true
               },
               "src/styles.scss",
               "src/assets/styles/app-loading.scss",
@@ -52,16 +59,17 @@
               "optimization": true,
               "outputHashing": "all",
               "sourceMap": false,
-              "extractCss": true,
               "namedChunks": false,
               "aot": true,
               "extractLicenses": true,
               "vendorChunk": false,
               "buildOptimizer": true,
-              "fileReplacements": [{
-                "replace": "src/environments/environment.ts",
-                "with": "src/environments/environment.prod.ts"
-              }]
+              "fileReplacements": [
+                {
+                  "replace": "src/environments/environment.ts",
+                  "with": "src/environments/environment.prod.ts"
+                }
+              ]
             }
           }
         },
@@ -90,8 +98,10 @@
             "polyfills": "src/polyfills.ts",
             "tsConfig": "src/tsconfig.spec.json",
             "scripts": [],
-            "styles": [{
-                "input": "node_modules/@angular/material/prebuilt-themes/deeppurple-amber.css"
+            "styles": [
+              {
+                "input": "node_modules/@angular/material/prebuilt-themes/deeppurple-amber.css",
+                "inject": true
               },
               "src/styles.scss",
               "src/assets/fonts/iconfont/material-icons.css"
diff --git a/services/self-service/src/main/resources/webapp/package-lock.json b/services/self-service/src/main/resources/webapp/package-lock.json
index 0dc0dfa..ebe622d 100644
--- a/services/self-service/src/main/resources/webapp/package-lock.json
+++ b/services/self-service/src/main/resources/webapp/package-lock.json
@@ -1,440 +1,929 @@
 {
   "name": "webapp",
   "version": "0.0.0",
-  "lockfileVersion": 1,
+  "lockfileVersion": 2,
   "requires": true,
-  "dependencies": {
-    "@angular-devkit/architect": {
-      "version": "0.1002.0",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1002.0.tgz",
-      "integrity": "sha512-twM8V03ujBIGVpgV1PBlSDodUdxtUb7WakutfWafAvEHUsgwzfvQz2VtKWvjNZ9AiYjnCuwkQaclqVv0VHNo9w==",
-      "dev": true,
-      "requires": {
-        "@angular-devkit/core": "10.2.0",
-        "rxjs": "6.6.2"
-      },
+  "packages": {
+    "": {
+      "name": "webapp",
+      "version": "0.0.0",
+      "license": "MIT",
       "dependencies": {
-        "rxjs": {
-          "version": "6.6.2",
-          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.2.tgz",
-          "integrity": "sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==",
-          "dev": true,
-          "requires": {
-            "tslib": "^1.9.0"
-          }
-        }
+        "@angular/animations": "^11.2.14",
+        "@angular/cdk": "^10.2.6",
+        "@angular/common": "^11.2.14",
+        "@angular/compiler": "^11.2.14",
+        "@angular/core": "^11.2.14",
+        "@angular/forms": "^11.2.14",
+        "@angular/localize": "^11.2.14",
+        "@angular/material": "^10.2.6",
+        "@angular/material-moment-adapter": "^10.2.6",
+        "@angular/platform-browser": "^11.2.14",
+        "@angular/platform-browser-dynamic": "^11.2.14",
+        "@angular/platform-server": "^11.2.14",
+        "@angular/router": "^11.2.14",
+        "core-js": "^3.6.5",
+        "guacamole-common-js": "^1.2.0",
+        "lodash.isequal": "^4.5.0",
+        "moment": "^2.29.4",
+        "moment-timezone": "^0.5.35",
+        "ng-daterangepicker": "^1.1.0",
+        "ng2-ace-editor": "^0.3.9",
+        "ngx-toastr": "^12.1.0",
+        "rxjs": "^6.6.3",
+        "rxjs-compat": "6.5.3",
+        "swagger-ui-dist": "^3.36.1",
+        "tslib": "^2.0.0",
+        "web-animations-js": "^2.3.2",
+        "zone.js": "^0.10.3"
+      },
+      "devDependencies": {
+        "@angular-devkit/build-angular": "^15.2.4",
+        "@angular/cli": "^11.2.19",
+        "@angular/compiler-cli": "^11.2.14",
+        "@types/moment-timezone": "^0.5.30",
+        "@types/node": "^12.11.1",
+        "codelyzer": "^6.0.0",
+        "ts-node": "~8.4.1",
+        "tslint": "^6.1.3",
+        "typescript": "^4.1.6",
+        "webpack-bundle-analyzer": "^4.7.0"
       }
     },
-    "@angular-devkit/build-angular": {
-      "version": "0.1002.0",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-0.1002.0.tgz",
-      "integrity": "sha512-cPkdp1GceokGHc79Wg0hACMqqmnJ4W3H9kY4c9qp1Xz18b3vk1aq09JNawOpfUN09S9vBCnn4glg22lRyqmJNA==",
+    "node_modules/@ampproject/remapping": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
+      "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.1.0",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@angular-devkit/architect": {
+      "version": "0.1102.19",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1102.19.tgz",
+      "integrity": "sha512-5Opv6H+XyCkuQvQ1jsxw416YqMDPX3dVonMarFGBPLBe8YEXLRTJ60dvmuLsLpWk6ccTd3XiNT7WEJy4ctDc2Q==",
       "dev": true,
-      "requires": {
-        "@angular-devkit/architect": "0.1002.0",
-        "@angular-devkit/build-optimizer": "0.1002.0",
-        "@angular-devkit/build-webpack": "0.1002.0",
-        "@angular-devkit/core": "10.2.0",
-        "@babel/core": "7.11.1",
-        "@babel/generator": "7.11.0",
-        "@babel/plugin-transform-runtime": "7.11.0",
-        "@babel/preset-env": "7.11.0",
-        "@babel/runtime": "7.11.2",
-        "@babel/template": "7.10.4",
-        "@jsdevtools/coverage-istanbul-loader": "3.0.5",
-        "@ngtools/webpack": "10.2.0",
-        "autoprefixer": "9.8.6",
-        "babel-loader": "8.1.0",
-        "browserslist": "^4.9.1",
-        "cacache": "15.0.5",
-        "caniuse-lite": "^1.0.30001032",
-        "circular-dependency-plugin": "5.2.0",
-        "copy-webpack-plugin": "6.0.3",
-        "core-js": "3.6.4",
-        "css-loader": "4.2.2",
-        "cssnano": "4.1.10",
-        "file-loader": "6.0.0",
-        "find-cache-dir": "3.3.1",
-        "glob": "7.1.6",
-        "jest-worker": "26.3.0",
+      "dependencies": {
+        "@angular-devkit/core": "11.2.19",
+        "rxjs": "6.6.3"
+      },
+      "engines": {
+        "node": ">= 10.13.0",
+        "npm": "^6.11.0 || ^7.5.6",
+        "yarn": ">= 1.13.0"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular": {
+      "version": "15.2.4",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-15.2.4.tgz",
+      "integrity": "sha512-wt0S4oz0vxuW0/Ak5X0vQ7s7TSPynmktVNJblu9SFRgwCD3kplV2B693F+M6t8eLzSy0UCSbZp9h3Ae8gLEiEw==",
+      "dev": true,
+      "dependencies": {
+        "@ampproject/remapping": "2.2.0",
+        "@angular-devkit/architect": "0.1502.4",
+        "@angular-devkit/build-webpack": "0.1502.4",
+        "@angular-devkit/core": "15.2.4",
+        "@babel/core": "7.20.12",
+        "@babel/generator": "7.20.14",
+        "@babel/helper-annotate-as-pure": "7.18.6",
+        "@babel/helper-split-export-declaration": "7.18.6",
+        "@babel/plugin-proposal-async-generator-functions": "7.20.7",
+        "@babel/plugin-transform-async-to-generator": "7.20.7",
+        "@babel/plugin-transform-runtime": "7.19.6",
+        "@babel/preset-env": "7.20.2",
+        "@babel/runtime": "7.20.13",
+        "@babel/template": "7.20.7",
+        "@discoveryjs/json-ext": "0.5.7",
+        "@ngtools/webpack": "15.2.4",
+        "ansi-colors": "4.1.3",
+        "autoprefixer": "10.4.13",
+        "babel-loader": "9.1.2",
+        "babel-plugin-istanbul": "6.1.1",
+        "browserslist": "4.21.5",
+        "cacache": "17.0.4",
+        "chokidar": "3.5.3",
+        "copy-webpack-plugin": "11.0.0",
+        "critters": "0.0.16",
+        "css-loader": "6.7.3",
+        "esbuild-wasm": "0.17.8",
+        "glob": "8.1.0",
+        "https-proxy-agent": "5.0.1",
+        "inquirer": "8.2.4",
+        "jsonc-parser": "3.2.0",
         "karma-source-map-support": "1.4.0",
-        "less-loader": "6.2.0",
-        "license-webpack-plugin": "2.3.0",
-        "loader-utils": "2.0.0",
-        "mini-css-extract-plugin": "0.10.0",
-        "minimatch": "3.0.4",
-        "open": "7.2.0",
-        "parse5": "6.0.1",
-        "parse5-htmlparser2-tree-adapter": "6.0.1",
-        "pnp-webpack-plugin": "1.6.4",
-        "postcss": "7.0.32",
-        "postcss-import": "12.0.1",
-        "postcss-loader": "3.0.0",
-        "raw-loader": "4.0.1",
-        "regenerator-runtime": "0.13.7",
-        "resolve-url-loader": "3.1.2",
-        "rimraf": "3.0.2",
-        "rollup": "2.26.5",
-        "rxjs": "6.6.2",
-        "sass": "1.26.10",
-        "sass-loader": "10.0.1",
-        "semver": "7.3.2",
-        "source-map": "0.7.3",
-        "source-map-loader": "1.0.2",
-        "source-map-support": "0.5.19",
-        "speed-measure-webpack-plugin": "1.3.3",
-        "style-loader": "1.2.1",
-        "stylus": "0.54.8",
-        "stylus-loader": "3.0.2",
-        "terser": "5.3.0",
-        "terser-webpack-plugin": "4.1.0",
+        "less": "4.1.3",
+        "less-loader": "11.1.0",
+        "license-webpack-plugin": "4.0.2",
+        "loader-utils": "3.2.1",
+        "magic-string": "0.29.0",
+        "mini-css-extract-plugin": "2.7.2",
+        "open": "8.4.1",
+        "ora": "5.4.1",
+        "parse5-html-rewriting-stream": "7.0.0",
+        "piscina": "3.2.0",
+        "postcss": "8.4.21",
+        "postcss-loader": "7.0.2",
+        "resolve-url-loader": "5.0.0",
+        "rxjs": "6.6.7",
+        "sass": "1.58.1",
+        "sass-loader": "13.2.0",
+        "semver": "7.3.8",
+        "source-map-loader": "4.0.1",
+        "source-map-support": "0.5.21",
+        "terser": "5.16.3",
+        "text-table": "0.2.0",
         "tree-kill": "1.2.2",
-        "webpack": "4.44.1",
-        "webpack-dev-middleware": "3.7.2",
-        "webpack-dev-server": "3.11.0",
-        "webpack-merge": "4.2.2",
-        "webpack-sources": "1.4.3",
-        "webpack-subresource-integrity": "1.4.1",
-        "worker-plugin": "5.0.0"
+        "tslib": "2.5.0",
+        "webpack": "5.76.1",
+        "webpack-dev-middleware": "6.0.1",
+        "webpack-dev-server": "4.11.1",
+        "webpack-merge": "5.8.0",
+        "webpack-subresource-integrity": "5.1.0"
       },
-      "dependencies": {
-        "@babel/core": {
-          "version": "7.11.1",
-          "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.1.tgz",
-          "integrity": "sha512-XqF7F6FWQdKGGWAzGELL+aCO1p+lRY5Tj5/tbT3St1G8NaH70jhhDIKknIZaDans0OQBG5wRAldROLHSt44BgQ==",
-          "dev": true,
-          "requires": {
-            "@babel/code-frame": "^7.10.4",
-            "@babel/generator": "^7.11.0",
-            "@babel/helper-module-transforms": "^7.11.0",
-            "@babel/helpers": "^7.10.4",
-            "@babel/parser": "^7.11.1",
-            "@babel/template": "^7.10.4",
-            "@babel/traverse": "^7.11.0",
-            "@babel/types": "^7.11.0",
-            "convert-source-map": "^1.7.0",
-            "debug": "^4.1.0",
-            "gensync": "^1.0.0-beta.1",
-            "json5": "^2.1.2",
-            "lodash": "^4.17.19",
-            "resolve": "^1.3.2",
-            "semver": "^5.4.1",
-            "source-map": "^0.5.0"
-          },
-          "dependencies": {
-            "semver": {
-              "version": "5.7.1",
-              "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
-              "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
-              "dev": true
-            },
-            "source-map": {
-              "version": "0.5.7",
-              "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-              "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-              "dev": true
-            }
-          }
+      "engines": {
+        "node": "^14.20.0 || ^16.13.0 || >=18.10.0",
+        "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+        "yarn": ">= 1.13.0"
+      },
+      "optionalDependencies": {
+        "esbuild": "0.17.8"
+      },
+      "peerDependencies": {
+        "@angular/compiler-cli": "^15.0.0",
+        "@angular/localize": "^15.0.0",
+        "@angular/platform-server": "^15.0.0",
+        "@angular/service-worker": "^15.0.0",
+        "karma": "^6.3.0",
+        "ng-packagr": "^15.0.0",
+        "protractor": "^7.0.0",
+        "tailwindcss": "^2.0.0 || ^3.0.0",
+        "typescript": ">=4.8.2 <5.0"
+      },
+      "peerDependenciesMeta": {
+        "@angular/localize": {
+          "optional": true
         },
-        "@babel/generator": {
-          "version": "7.11.0",
-          "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.0.tgz",
-          "integrity": "sha512-fEm3Uzw7Mc9Xi//qU20cBKatTfs2aOtKqmvy/Vm7RkJEGFQ4xc9myCfbXxqK//ZS8MR/ciOHw6meGASJuKmDfQ==",
-          "dev": true,
-          "requires": {
-            "@babel/types": "^7.11.0",
-            "jsesc": "^2.5.1",
-            "source-map": "^0.5.0"
-          },
-          "dependencies": {
-            "source-map": {
-              "version": "0.5.7",
-              "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-              "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-              "dev": true
-            }
-          }
+        "@angular/platform-server": {
+          "optional": true
         },
-        "core-js": {
-          "version": "3.6.4",
-          "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.4.tgz",
-          "integrity": "sha512-4paDGScNgZP2IXXilaffL9X7968RuvwlkK3xWtZRVqgd8SYNiVKRJvkFd1aqqEuPfN7E68ZHEp9hDj6lHj4Hyw==",
-          "dev": true
+        "@angular/service-worker": {
+          "optional": true
         },
-        "glob": {
-          "version": "7.1.6",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
+        "karma": {
+          "optional": true
         },
-        "parse5": {
-          "version": "6.0.1",
-          "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
-          "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
-          "dev": true
+        "ng-packagr": {
+          "optional": true
         },
-        "rxjs": {
-          "version": "6.6.2",
-          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.2.tgz",
-          "integrity": "sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==",
-          "dev": true,
-          "requires": {
-            "tslib": "^1.9.0"
-          }
+        "protractor": {
+          "optional": true
         },
-        "semver": {
-          "version": "7.3.2",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
-          "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.7.3",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
-          "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
-          "dev": true
+        "tailwindcss": {
+          "optional": true
         }
       }
     },
-    "@angular-devkit/build-optimizer": {
-      "version": "0.1002.0",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.1002.0.tgz",
-      "integrity": "sha512-ACnm9doPMbRtSy1UZN5ir7smeLMx0g0oW7jX3jyPepeQKZ+9U1Bn09t10NLZQH+Z509jWZgvNJH/aOh85P6euw==",
+    "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/architect": {
+      "version": "0.1502.4",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1502.4.tgz",
+      "integrity": "sha512-bDBcaRMBfXFfK9MpvfNO926F1rL0PEw+mveXxq3/SSql+1XP/hrc5TVGwnoim4g6DqsGmu9upS5DyJ6PnL/hHA==",
       "dev": true,
-      "requires": {
-        "loader-utils": "2.0.0",
-        "source-map": "0.7.3",
-        "tslib": "2.0.1",
-        "typescript": "4.0.2",
-        "webpack-sources": "1.4.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==",
-          "dev": true
-        },
-        "tslib": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.1.tgz",
-          "integrity": "sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==",
-          "dev": true
-        },
-        "typescript": {
-          "version": "4.0.2",
-          "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.0.2.tgz",
-          "integrity": "sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==",
-          "dev": true
+        "@angular-devkit/core": "15.2.4",
+        "rxjs": "6.6.7"
+      },
+      "engines": {
+        "node": "^14.20.0 || ^16.13.0 || >=18.10.0",
+        "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+        "yarn": ">= 1.13.0"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": {
+      "version": "15.2.4",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.2.4.tgz",
+      "integrity": "sha512-yl+0j1bMwJLKShsyCXw77tbJG8Sd21+itisPLL2MgEpLNAO252kr9zG4TLlFRJyKVftm2l1h78KjqvM5nbOXNg==",
+      "dev": true,
+      "dependencies": {
+        "ajv": "8.12.0",
+        "ajv-formats": "2.1.1",
+        "jsonc-parser": "3.2.0",
+        "rxjs": "6.6.7",
+        "source-map": "0.7.4"
+      },
+      "engines": {
+        "node": "^14.20.0 || ^16.13.0 || >=18.10.0",
+        "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+        "yarn": ">= 1.13.0"
+      },
+      "peerDependencies": {
+        "chokidar": "^3.5.2"
+      },
+      "peerDependenciesMeta": {
+        "chokidar": {
+          "optional": true
         }
       }
     },
-    "@angular-devkit/build-webpack": {
-      "version": "0.1002.0",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1002.0.tgz",
-      "integrity": "sha512-TLBBQ6ANOLKXOPxpCOnxAtoknwHA7XhsLuueN06w5qqF+QNNbWUMPoieKFGs2TnotfCgbiq6x57IDEZTyT6V0w==",
+    "node_modules/@angular-devkit/build-angular/node_modules/@ngtools/webpack": {
+      "version": "15.2.4",
+      "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-15.2.4.tgz",
+      "integrity": "sha512-cQ7MsRoGJgPOVnpvFgWhygeSe6zJ0ITiUhjmmuOgpNDfYkrgYxN3Ot/qvQefFei+oGZ1JJ9bRb8lcPKL/apoBQ==",
       "dev": true,
-      "requires": {
-        "@angular-devkit/architect": "0.1002.0",
-        "@angular-devkit/core": "10.2.0",
-        "rxjs": "6.6.2"
+      "engines": {
+        "node": "^14.20.0 || ^16.13.0 || >=18.10.0",
+        "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+        "yarn": ">= 1.13.0"
       },
+      "peerDependencies": {
+        "@angular/compiler-cli": "^15.0.0",
+        "typescript": ">=4.8.2 <5.0",
+        "webpack": "^5.54.0"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/ajv": {
+      "version": "8.12.0",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+      "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+      "dev": true,
       "dependencies": {
-        "rxjs": {
-          "version": "6.6.2",
-          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.2.tgz",
-          "integrity": "sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==",
-          "dev": true,
-          "requires": {
-            "tslib": "^1.9.0"
-          }
+        "fast-deep-equal": "^3.1.1",
+        "json-schema-traverse": "^1.0.0",
+        "require-from-string": "^2.0.2",
+        "uri-js": "^4.2.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/ansi-colors": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
+      "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/babel-loader": {
+      "version": "9.1.2",
+      "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.2.tgz",
+      "integrity": "sha512-mN14niXW43tddohGl8HPu5yfQq70iUThvFL/4QzESA7GcZoC0eVOhvWdQ8+3UlSjaDE9MVtsW9mxDY07W7VpVA==",
+      "dev": true,
+      "dependencies": {
+        "find-cache-dir": "^3.3.2",
+        "schema-utils": "^4.0.0"
+      },
+      "engines": {
+        "node": ">= 14.15.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.12.0",
+        "webpack": ">=5"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/brace-expansion": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+      "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/cacache": {
+      "version": "17.0.4",
+      "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.0.4.tgz",
+      "integrity": "sha512-Z/nL3gU+zTUjz5pCA5vVjYM8pmaw2kxM7JEiE0fv3w77Wj+sFbi70CrBruUWH0uNcEdvLDixFpgA2JM4F4DBjA==",
+      "dev": true,
+      "dependencies": {
+        "@npmcli/fs": "^3.1.0",
+        "fs-minipass": "^3.0.0",
+        "glob": "^8.0.1",
+        "lru-cache": "^7.7.1",
+        "minipass": "^4.0.0",
+        "minipass-collect": "^1.0.2",
+        "minipass-flush": "^1.0.5",
+        "minipass-pipeline": "^1.2.4",
+        "p-map": "^4.0.0",
+        "promise-inflight": "^1.0.1",
+        "ssri": "^10.0.0",
+        "tar": "^6.1.11",
+        "unique-filename": "^3.0.0"
+      },
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/cacache/node_modules/lru-cache": {
+      "version": "7.14.1",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz",
+      "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/fs-minipass": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.1.tgz",
+      "integrity": "sha512-MhaJDcFRTuLidHrIttu0RDGyyXs/IYHVmlcxfLAEFIWjc1vdLAkdwT7Ace2u7DbitWC0toKMl5eJZRYNVreIMw==",
+      "dev": true,
+      "dependencies": {
+        "minipass": "^4.0.0"
+      },
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/glob": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
+      "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+      "dev": true,
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^5.0.1",
+        "once": "^1.3.0"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/inquirer": {
+      "version": "8.2.4",
+      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz",
+      "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==",
+      "dev": true,
+      "dependencies": {
+        "ansi-escapes": "^4.2.1",
+        "chalk": "^4.1.1",
+        "cli-cursor": "^3.1.0",
+        "cli-width": "^3.0.0",
+        "external-editor": "^3.0.3",
+        "figures": "^3.0.0",
+        "lodash": "^4.17.21",
+        "mute-stream": "0.0.8",
+        "ora": "^5.4.1",
+        "run-async": "^2.4.0",
+        "rxjs": "^7.5.5",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0",
+        "through": "^2.3.6",
+        "wrap-ansi": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/inquirer/node_modules/rxjs": {
+      "version": "7.8.0",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz",
+      "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==",
+      "dev": true,
+      "dependencies": {
+        "tslib": "^2.1.0"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/json-schema-traverse": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+      "dev": true
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/jsonc-parser": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
+      "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==",
+      "dev": true
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/magic-string": {
+      "version": "0.29.0",
+      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.29.0.tgz",
+      "integrity": "sha512-WcfidHrDjMY+eLjlU+8OvwREqHwpgCeKVBUpQ3OhYYuvfaYCUgcbuBzappNzZvg/v8onU3oQj+BYpkOJe9Iw4Q==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.4.13"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/minimatch": {
+      "version": "5.1.6",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+      "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/minipass": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.3.tgz",
+      "integrity": "sha512-OW2r4sQ0sI+z5ckEt5c1Tri4xTgZwYDxpE54eqWlQloQRoWtXjqt9udJ5Z4dSv7wK+nfFI7FRXyCpBSft+gpFw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/open": {
+      "version": "8.4.1",
+      "resolved": "https://registry.npmjs.org/open/-/open-8.4.1.tgz",
+      "integrity": "sha512-/4b7qZNhv6Uhd7jjnREh1NjnPxlTq+XNWPG88Ydkj5AILcA5m3ajvcg57pB24EQjKv0dK62XnDqk9c/hkIG5Kg==",
+      "dev": true,
+      "dependencies": {
+        "define-lazy-prop": "^2.0.0",
+        "is-docker": "^2.1.1",
+        "is-wsl": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/ora": {
+      "version": "5.4.1",
+      "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
+      "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==",
+      "dev": true,
+      "dependencies": {
+        "bl": "^4.1.0",
+        "chalk": "^4.1.0",
+        "cli-cursor": "^3.1.0",
+        "cli-spinners": "^2.5.0",
+        "is-interactive": "^1.0.0",
+        "is-unicode-supported": "^0.1.0",
+        "log-symbols": "^4.1.0",
+        "strip-ansi": "^6.0.0",
+        "wcwidth": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/rxjs": {
+      "version": "6.6.7",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+      "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+      "dev": true,
+      "dependencies": {
+        "tslib": "^1.9.0"
+      },
+      "engines": {
+        "npm": ">=2.0.0"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/rxjs/node_modules/tslib": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+      "dev": true
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/semver": {
+      "version": "7.3.8",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/source-map": {
+      "version": "0.7.4",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
+      "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/ssri": {
+      "version": "10.0.1",
+      "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.1.tgz",
+      "integrity": "sha512-WVy6di9DlPOeBWEjMScpNipeSX2jIZBGEn5Uuo8Q7aIuFEuDX0pw8RxcOjlD1TWP4obi24ki7m/13+nFpcbXrw==",
+      "dev": true,
+      "dependencies": {
+        "minipass": "^4.0.0"
+      },
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/tslib": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
+      "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==",
+      "dev": true
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/unique-filename": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz",
+      "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==",
+      "dev": true,
+      "dependencies": {
+        "unique-slug": "^4.0.0"
+      },
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@angular-devkit/build-angular/node_modules/unique-slug": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz",
+      "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==",
+      "dev": true,
+      "dependencies": {
+        "imurmurhash": "^0.1.4"
+      },
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@angular-devkit/build-webpack": {
+      "version": "0.1502.4",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1502.4.tgz",
+      "integrity": "sha512-Bs/pxcY3517QAVyAalDxJgjc93KWQos+dFdgEQrKxj/VTs1BTYnLbb2M8Y7MoxVnfH4S+qqxGe5B57T+TlB3Eg==",
+      "dev": true,
+      "dependencies": {
+        "@angular-devkit/architect": "0.1502.4",
+        "rxjs": "6.6.7"
+      },
+      "engines": {
+        "node": "^14.20.0 || ^16.13.0 || >=18.10.0",
+        "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+        "yarn": ">= 1.13.0"
+      },
+      "peerDependencies": {
+        "webpack": "^5.30.0",
+        "webpack-dev-server": "^4.0.0"
+      }
+    },
+    "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/architect": {
+      "version": "0.1502.4",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1502.4.tgz",
+      "integrity": "sha512-bDBcaRMBfXFfK9MpvfNO926F1rL0PEw+mveXxq3/SSql+1XP/hrc5TVGwnoim4g6DqsGmu9upS5DyJ6PnL/hHA==",
+      "dev": true,
+      "dependencies": {
+        "@angular-devkit/core": "15.2.4",
+        "rxjs": "6.6.7"
+      },
+      "engines": {
+        "node": "^14.20.0 || ^16.13.0 || >=18.10.0",
+        "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+        "yarn": ">= 1.13.0"
+      }
+    },
+    "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/core": {
+      "version": "15.2.4",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.2.4.tgz",
+      "integrity": "sha512-yl+0j1bMwJLKShsyCXw77tbJG8Sd21+itisPLL2MgEpLNAO252kr9zG4TLlFRJyKVftm2l1h78KjqvM5nbOXNg==",
+      "dev": true,
+      "dependencies": {
+        "ajv": "8.12.0",
+        "ajv-formats": "2.1.1",
+        "jsonc-parser": "3.2.0",
+        "rxjs": "6.6.7",
+        "source-map": "0.7.4"
+      },
+      "engines": {
+        "node": "^14.20.0 || ^16.13.0 || >=18.10.0",
+        "npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
+        "yarn": ">= 1.13.0"
+      },
+      "peerDependencies": {
+        "chokidar": "^3.5.2"
+      },
+      "peerDependenciesMeta": {
+        "chokidar": {
+          "optional": true
         }
       }
     },
-    "@angular-devkit/core": {
-      "version": "10.2.0",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-10.2.0.tgz",
-      "integrity": "sha512-XAszFhSF3mZw1VjoOsYGbArr5NJLcStjOvcCGjBPl1UBM2AKpuCQXHxI9XJGYKL3B93Vp5G58d8qkHvamT53OA==",
+    "node_modules/@angular-devkit/build-webpack/node_modules/ajv": {
+      "version": "8.12.0",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+      "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
       "dev": true,
-      "requires": {
-        "ajv": "6.12.4",
+      "dependencies": {
+        "fast-deep-equal": "^3.1.1",
+        "json-schema-traverse": "^1.0.0",
+        "require-from-string": "^2.0.2",
+        "uri-js": "^4.2.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/@angular-devkit/build-webpack/node_modules/json-schema-traverse": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+      "dev": true
+    },
+    "node_modules/@angular-devkit/build-webpack/node_modules/jsonc-parser": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
+      "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==",
+      "dev": true
+    },
+    "node_modules/@angular-devkit/build-webpack/node_modules/rxjs": {
+      "version": "6.6.7",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+      "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+      "dev": true,
+      "dependencies": {
+        "tslib": "^1.9.0"
+      },
+      "engines": {
+        "npm": ">=2.0.0"
+      }
+    },
+    "node_modules/@angular-devkit/build-webpack/node_modules/source-map": {
+      "version": "0.7.4",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
+      "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@angular-devkit/build-webpack/node_modules/tslib": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+      "dev": true
+    },
+    "node_modules/@angular-devkit/core": {
+      "version": "11.2.19",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.2.19.tgz",
+      "integrity": "sha512-kvS0QXDYDatLyf0NYv2sahPYD7kya4g5GpQAV1ddjjLmEVeZssHt+Xfk2tzrkzYzqRMiyspx3HPPrrOnMUAFhQ==",
+      "dev": true,
+      "dependencies": {
+        "ajv": "6.12.6",
         "fast-json-stable-stringify": "2.1.0",
         "magic-string": "0.25.7",
-        "rxjs": "6.6.2",
+        "rxjs": "6.6.3",
         "source-map": "0.7.3"
       },
-      "dependencies": {
-        "rxjs": {
-          "version": "6.6.2",
-          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.2.tgz",
-          "integrity": "sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==",
-          "dev": true,
-          "requires": {
-            "tslib": "^1.9.0"
-          }
-        },
-        "source-map": {
-          "version": "0.7.3",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
-          "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
-          "dev": true
-        }
+      "engines": {
+        "node": ">= 10.13.0",
+        "npm": "^6.11.0 || ^7.5.6",
+        "yarn": ">= 1.13.0"
       }
     },
-    "@angular-devkit/schematics": {
-      "version": "10.2.0",
-      "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-10.2.0.tgz",
-      "integrity": "sha512-TQI5NnE6iM3ChF5gZQ9qb+lZgMWa7aLoF5ksOyT3zrmOuICiQYJhA6SsjV95q7J4M55qYymwBib8KTqU/xuQww==",
+    "node_modules/@angular-devkit/core/node_modules/source-map": {
+      "version": "0.7.3",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
+      "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
       "dev": true,
-      "requires": {
-        "@angular-devkit/core": "10.2.0",
-        "ora": "5.0.0",
-        "rxjs": "6.6.2"
-      },
-      "dependencies": {
-        "rxjs": {
-          "version": "6.6.2",
-          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.2.tgz",
-          "integrity": "sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg==",
-          "dev": true,
-          "requires": {
-            "tslib": "^1.9.0"
-          }
-        }
+      "engines": {
+        "node": ">= 8"
       }
     },
-    "@angular/animations": {
-      "version": "10.2.2",
-      "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-10.2.2.tgz",
-      "integrity": "sha512-vxDbDeGggYeK5YXuBrzeZEO4nrZoQlJfgdUBGPNJmz97ZgX0sgjbmt3y/S7qupHNwdV4QExkaXRlGk0wcYuEqQ==",
-      "requires": {
+    "node_modules/@angular-devkit/schematics": {
+      "version": "11.2.19",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-11.2.19.tgz",
+      "integrity": "sha512-jefsjIlaznKxn5+dHSMwvXTO+QKCKtahu/iZoRcdb25JWGXrkj8/quCuj4VeMFY48g/EPjX+9WhDtRl8TjYBiA==",
+      "dev": true,
+      "dependencies": {
+        "@angular-devkit/core": "11.2.19",
+        "ora": "5.3.0",
+        "rxjs": "6.6.3"
+      },
+      "engines": {
+        "node": ">= 10.13.0",
+        "npm": "^6.11.0 || ^7.5.6",
+        "yarn": ">= 1.13.0"
+      }
+    },
+    "node_modules/@angular/animations": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-11.2.14.tgz",
+      "integrity": "sha512-Heq/nNrCmb3jbkusu+BQszOecfFI/31Oxxj+CDQkqqYpBcswk6bOJLoEE472o+vmgxaXbgeflU9qbIiCQhpMFA==",
+      "dependencies": {
         "tslib": "^2.0.0"
       },
-      "dependencies": {
-        "tslib": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
-          "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
-        }
+      "peerDependencies": {
+        "@angular/core": "11.2.14"
       }
     },
-    "@angular/cdk": {
+    "node_modules/@angular/cdk": {
       "version": "10.2.7",
       "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-10.2.7.tgz",
       "integrity": "sha512-ZQjDfTRTn7JuAKsf3jiIdU2XBaxxGBi/ZWYv5Pb3HCl6B4PISsIE5VWRhkoUogoAB0MiFHpjnWeIqknJEm11YQ==",
-      "requires": {
-        "parse5": "^5.0.0",
+      "dependencies": {
         "tslib": "^2.0.0"
       },
-      "dependencies": {
-        "tslib": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
-          "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
-        }
+      "optionalDependencies": {
+        "parse5": "^5.0.0"
+      },
+      "peerDependencies": {
+        "@angular/common": "^10.0.0 || ^11.0.0-0",
+        "@angular/core": "^10.0.0 || ^11.0.0-0"
       }
     },
-    "@angular/cli": {
-      "version": "10.2.0",
-      "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-10.2.0.tgz",
-      "integrity": "sha512-YBzwkFBmG6CdUJk8onsPXxHX/ByU5MERBQgYhLC873e2nZlXMUu+Ttq2Wai6apyskGvsXKxZNPOQSFZTGKXzXg==",
+    "node_modules/@angular/cli": {
+      "version": "11.2.19",
+      "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-11.2.19.tgz",
+      "integrity": "sha512-B7ZRmcleBF/D6ojt+LOfHE/2Cs3jpHWK/Khho0c2i1jrqLjCTFlgGfK0NKztbFr0lmbhL6Z7Oj4ge3X6dMcSuQ==",
       "dev": true,
-      "requires": {
-        "@angular-devkit/architect": "0.1002.0",
-        "@angular-devkit/core": "10.2.0",
-        "@angular-devkit/schematics": "10.2.0",
-        "@schematics/angular": "10.2.0",
-        "@schematics/update": "0.1002.0",
+      "hasInstallScript": true,
+      "dependencies": {
+        "@angular-devkit/architect": "0.1102.19",
+        "@angular-devkit/core": "11.2.19",
+        "@angular-devkit/schematics": "11.2.19",
+        "@schematics/angular": "11.2.19",
+        "@schematics/update": "0.1102.19",
         "@yarnpkg/lockfile": "1.1.0",
         "ansi-colors": "4.1.1",
-        "debug": "4.1.1",
-        "ini": "1.3.5",
+        "debug": "4.3.1",
+        "ini": "2.0.0",
         "inquirer": "7.3.3",
-        "npm-package-arg": "8.0.1",
+        "jsonc-parser": "3.0.0",
+        "npm-package-arg": "8.1.0",
         "npm-pick-manifest": "6.1.0",
-        "open": "7.2.0",
-        "pacote": "9.5.12",
-        "read-package-tree": "5.3.1",
+        "open": "7.4.0",
+        "ora": "5.3.0",
+        "pacote": "11.2.4",
+        "resolve": "1.19.0",
         "rimraf": "3.0.2",
-        "semver": "7.3.2",
-        "symbol-observable": "1.2.0",
+        "semver": "7.3.4",
+        "symbol-observable": "3.0.0",
         "universal-analytics": "0.4.23",
-        "uuid": "8.3.0"
+        "uuid": "8.3.2"
       },
-      "dependencies": {
-        "ansi-colors": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
-          "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
-          "dev": true
-        },
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "semver": {
-          "version": "7.3.2",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
-          "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
-          "dev": true
-        },
-        "uuid": {
-          "version": "8.3.0",
-          "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.0.tgz",
-          "integrity": "sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ==",
-          "dev": true
-        }
+      "bin": {
+        "ng": "bin/ng"
+      },
+      "engines": {
+        "node": ">= 10.13.0",
+        "npm": "^6.11.0 || ^7.5.6",
+        "yarn": ">= 1.13.0"
       }
     },
-    "@angular/common": {
-      "version": "10.2.2",
-      "resolved": "https://registry.npmjs.org/@angular/common/-/common-10.2.2.tgz",
-      "integrity": "sha512-iV5kTGg7Xe79iih0RzulNFgDhyCgqpf0GC9MsWm663sYfeKaGmO0++O4FKCahE4N/++7thRMFgXy9PpSYDrFfg==",
-      "requires": {
-        "tslib": "^2.0.0"
-      },
-      "dependencies": {
-        "tslib": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
-          "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
-        }
-      }
-    },
-    "@angular/compiler": {
-      "version": "10.2.2",
-      "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-10.2.2.tgz",
-      "integrity": "sha512-62wb/aj8ORaUyVcI6cxf07gBc3/hb+bVGl9Yni51e8//G2W7gleyQAXtIeZsT9NHi0KX1nKdXvUVwAoq4u7eHw==",
-      "requires": {
-        "tslib": "^2.0.0"
-      },
-      "dependencies": {
-        "tslib": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
-          "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
-        }
-      }
-    },
-    "@angular/compiler-cli": {
-      "version": "10.2.2",
-      "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-10.2.2.tgz",
-      "integrity": "sha512-Erbb7Rs5fo+7/gG1WPwtO5UfSq8qtBBucGu9da/HQLJdw5AO/5pKRl4PLQlxjSopsb8eRC+yVpt9OlCYaY2Chg==",
+    "node_modules/@angular/cli/node_modules/debug": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+      "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
       "dev": true,
-      "requires": {
+      "dependencies": {
+        "ms": "2.1.2"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@angular/cli/node_modules/semver": {
+      "version": "7.3.4",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
+      "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@angular/cli/node_modules/uuid": {
+      "version": "8.3.2",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+      "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+      "dev": true,
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
+    "node_modules/@angular/common": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/common/-/common-11.2.14.tgz",
+      "integrity": "sha512-ZSLV/3j7eCTyLf/8g4yBFLWySjiLz3vLJAGWscYoUpnJWMnug1VRu6zoF/COxCbtORgE+Wz6K0uhfS6MziBGVw==",
+      "dependencies": {
+        "tslib": "^2.0.0"
+      },
+      "peerDependencies": {
+        "@angular/core": "11.2.14",
+        "rxjs": "^6.5.3"
+      }
+    },
+    "node_modules/@angular/compiler": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-11.2.14.tgz",
+      "integrity": "sha512-XBOK3HgA+/y6Cz7kOX4zcJYmgJ264XnfcbXUMU2cD7Ac+mbNhLPKohWrEiSWalfcjnpf5gRfufQrQP7lpAGu0A==",
+      "dependencies": {
+        "tslib": "^2.0.0"
+      }
+    },
+    "node_modules/@angular/compiler-cli": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-11.2.14.tgz",
+      "integrity": "sha512-A7ltnCp03/EVqK/Q3tVUDsokgz5GHW3dSPGl0Csk7Ys5uBB9ibHTmVt4eiXA4jt0+6Bk+mKxwe5BEDqLvwYFAg==",
+      "dependencies": {
+        "@babel/core": "^7.8.6",
+        "@babel/types": "^7.8.6",
         "canonical-path": "1.0.0",
         "chokidar": "^3.0.0",
         "convert-source-map": "^1.5.1",
@@ -447,180 +936,90 @@
         "source-map": "^0.6.1",
         "sourcemap-codec": "^1.4.8",
         "tslib": "^2.0.0",
-        "yargs": "15.3.0"
+        "yargs": "^16.2.0"
       },
-      "dependencies": {
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        },
-        "tslib": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
-          "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==",
-          "dev": true
-        }
+      "bin": {
+        "ivy-ngcc": "ngcc/main-ivy-ngcc.js",
+        "ng-xi18n": "src/extract_i18n.js",
+        "ngc": "src/main.js",
+        "ngcc": "ngcc/main-ngcc.js"
+      },
+      "engines": {
+        "node": ">=10.0"
+      },
+      "peerDependencies": {
+        "@angular/compiler": "11.2.14",
+        "typescript": ">=4.0 <4.2"
       }
     },
-    "@angular/core": {
-      "version": "10.2.2",
-      "resolved": "https://registry.npmjs.org/@angular/core/-/core-10.2.2.tgz",
-      "integrity": "sha512-9IHZF4/zcCKCLGzsbaUeNE8V+R9kcCu0ZNXvqkxd1+vTPdcf00185KzD6CAm+OiskLwvmrudh4vh0CQ+JHSTtQ==",
-      "requires": {
+    "node_modules/@angular/compiler-cli/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@angular/compiler-cli/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/@angular/core": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/core/-/core-11.2.14.tgz",
+      "integrity": "sha512-vpR4XqBGitk1Faph37CSpemwIYTmJ3pdIVNoHKP6jLonpWu+0azkchf0f7oD8/2ivj2F81opcIw0tcsy/D/5Vg==",
+      "dependencies": {
         "tslib": "^2.0.0"
       },
-      "dependencies": {
-        "tslib": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
-          "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
-        }
+      "peerDependencies": {
+        "rxjs": "^6.5.3",
+        "zone.js": "^0.10.2 || ^0.11.3"
       }
     },
-    "@angular/forms": {
-      "version": "10.2.2",
-      "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-10.2.2.tgz",
-      "integrity": "sha512-ATPMEvM1I/oEXn24qyHpgihYsXrXqnBXJkIGMFb4Tty2ay9xWDtV9aDknvd/7In1/SbHwcSdwhfJJ43apDB6yg==",
-      "requires": {
+    "node_modules/@angular/forms": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-11.2.14.tgz",
+      "integrity": "sha512-4LWqY6KEIk1AZQFnk+4PJSOCamlD4tumuVN06gO4D0dZo9Cx+GcvW6pM6N0CPubRvPs3sScCnu20WT11HNWC1w==",
+      "dependencies": {
         "tslib": "^2.0.0"
       },
-      "dependencies": {
-        "tslib": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
-          "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
-        }
+      "peerDependencies": {
+        "@angular/common": "11.2.14",
+        "@angular/core": "11.2.14",
+        "@angular/platform-browser": "11.2.14",
+        "rxjs": "^6.5.3"
       }
     },
-    "@angular/localize": {
-      "version": "10.2.2",
-      "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-10.2.2.tgz",
-      "integrity": "sha512-QZSr0CNurtZYcmm15sIIcTiX2x3eewEQHyYv8+wxB8sw4qtTPR3OiQM/99ndyfNrhhQKWeq2qFxcp5sgUCFW5g==",
-      "requires": {
+    "node_modules/@angular/localize": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-11.2.14.tgz",
+      "integrity": "sha512-ssMuquxxqxA98LgEICEO/3JdmSflWxu5rlm/HPo28bnGiZ4IzDamZjJ1cu4S6RgsonJ1drB3Z8wkidXfEYZiWA==",
+      "dependencies": {
         "@babel/core": "7.8.3",
         "glob": "7.1.2",
-        "yargs": "15.3.0"
-      }
-    },
-    "@angular/material": {
-      "version": "10.2.7",
-      "resolved": "https://registry.npmjs.org/@angular/material/-/material-10.2.7.tgz",
-      "integrity": "sha512-uk6JkRrKHaM9VFMzX7pWC83YNLVgXPB3D8U1yjSOafCdWwrRZgUHGr8MPlSILCr3o2nxgg5SsKdWcWwHuXXUZA==",
-      "requires": {
-        "tslib": "^2.0.0"
+        "yargs": "^16.2.0"
       },
-      "dependencies": {
-        "tslib": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
-          "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
-        }
-      }
-    },
-    "@angular/material-moment-adapter": {
-      "version": "10.2.7",
-      "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-10.2.7.tgz",
-      "integrity": "sha512-VaigAiBCz10AvpzgZvdR4SCGnMRxXKx8ukUdeowuoqAFONEPpRdCJmwZ+8bpi9Q/jXlrZJicCMhklj4bBQw6tg==",
-      "requires": {
-        "tslib": "^2.0.0"
+      "bin": {
+        "localize-extract": "src/tools/src/extract/main.js",
+        "localize-translate": "src/tools/src/translate/main.js"
       },
-      "dependencies": {
-        "tslib": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
-          "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
-        }
-      }
-    },
-    "@angular/platform-browser": {
-      "version": "10.2.2",
-      "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-10.2.2.tgz",
-      "integrity": "sha512-vxUKppRS5rIytzp8rV7pcqobopqBqSpXd5Rv/C5yVU9fTqg/hxbMPF8fRDITRqhArtuT7iT3Vv3TK+whqXTyNQ==",
-      "requires": {
-        "tslib": "^2.0.0"
+      "engines": {
+        "node": ">=8.0"
       },
-      "dependencies": {
-        "tslib": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
-          "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
-        }
+      "peerDependencies": {
+        "@angular/compiler": "11.2.14",
+        "@angular/compiler-cli": "11.2.14"
       }
     },
-    "@angular/platform-browser-dynamic": {
-      "version": "10.2.2",
-      "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-10.2.2.tgz",
-      "integrity": "sha512-+Py/UhIOjsGvOozUFrCS/roAXLwSoE+moiJIxZkMrVVaRx/72P91bF3Zd17kYiXUGyEe7Im5NpXzWeK6y16oRg==",
-      "requires": {
-        "tslib": "^2.0.0"
-      },
-      "dependencies": {
-        "tslib": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
-          "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
-        }
-      }
-    },
-    "@angular/platform-server": {
-      "version": "10.2.2",
-      "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-10.2.2.tgz",
-      "integrity": "sha512-k8rHF7+jP2anICYoGRX/PGL++/1mNQBmG/kFprtYX6KGqLLoDGrfOp+atHtZIWtFclTuVKq9Xip1uiBwoGz64Q==",
-      "requires": {
-        "domino": "^2.1.2",
-        "tslib": "^2.0.0",
-        "xhr2": "^0.2.0"
-      },
-      "dependencies": {
-        "tslib": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
-          "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
-        }
-      }
-    },
-    "@angular/router": {
-      "version": "10.2.2",
-      "resolved": "https://registry.npmjs.org/@angular/router/-/router-10.2.2.tgz",
-      "integrity": "sha512-jskLB4B3ccJS9YUFGgrR8JC6Ae31U1iw6gefh/S0xP742IxhgexxrxDUu/NAZkLV51sQ++snpnUK9DZU1kpXmA==",
-      "requires": {
-        "tslib": "^2.0.0"
-      },
-      "dependencies": {
-        "tslib": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
-          "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
-        }
-      }
-    },
-    "@babel/code-frame": {
-      "version": "7.10.4",
-      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz",
-      "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==",
-      "requires": {
-        "@babel/highlight": "^7.10.4"
-      }
-    },
-    "@babel/compat-data": {
-      "version": "7.12.5",
-      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.12.5.tgz",
-      "integrity": "sha512-DTsS7cxrsH3by8nqQSpFSyjSfSYl57D6Cf4q8dW3LK83tBKBDCkfcay1nYkXq1nIHXnpX8WMMb/O25HOy3h1zg==",
-      "dev": true
-    },
-    "@babel/core": {
+    "node_modules/@angular/localize/node_modules/@babel/core": {
       "version": "7.8.3",
       "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.3.tgz",
       "integrity": "sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA==",
-      "requires": {
+      "dependencies": {
         "@babel/code-frame": "^7.8.3",
         "@babel/generator": "^7.8.3",
         "@babel/helpers": "^7.8.3",
@@ -636,407 +1035,11885 @@
         "resolve": "^1.3.2",
         "semver": "^5.4.1",
         "source-map": "^0.5.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/babel"
+      }
+    },
+    "node_modules/@angular/material": {
+      "version": "10.2.7",
+      "resolved": "https://registry.npmjs.org/@angular/material/-/material-10.2.7.tgz",
+      "integrity": "sha512-uk6JkRrKHaM9VFMzX7pWC83YNLVgXPB3D8U1yjSOafCdWwrRZgUHGr8MPlSILCr3o2nxgg5SsKdWcWwHuXXUZA==",
+      "dependencies": {
+        "tslib": "^2.0.0"
+      },
+      "peerDependencies": {
+        "@angular/animations": "^10.0.0 || ^11.0.0-0",
+        "@angular/cdk": "10.2.7",
+        "@angular/common": "^10.0.0 || ^11.0.0-0",
+        "@angular/core": "^10.0.0 || ^11.0.0-0",
+        "@angular/forms": "^10.0.0 || ^11.0.0-0"
+      }
+    },
+    "node_modules/@angular/material-moment-adapter": {
+      "version": "10.2.7",
+      "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-10.2.7.tgz",
+      "integrity": "sha512-VaigAiBCz10AvpzgZvdR4SCGnMRxXKx8ukUdeowuoqAFONEPpRdCJmwZ+8bpi9Q/jXlrZJicCMhklj4bBQw6tg==",
+      "dependencies": {
+        "tslib": "^2.0.0"
+      },
+      "peerDependencies": {
+        "@angular/core": "^10.0.0 || ^11.0.0-0",
+        "@angular/material": "10.2.7",
+        "moment": "^2.18.1"
+      }
+    },
+    "node_modules/@angular/platform-browser": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-11.2.14.tgz",
+      "integrity": "sha512-fb7b7ss/gRoP8wLAN17W62leMgjynuyjEPU2eUoAAazsG9f2cgM+z3rK29GYncDVyYQxZUZYnjSqvL6GSXx86A==",
+      "dependencies": {
+        "tslib": "^2.0.0"
+      },
+      "peerDependencies": {
+        "@angular/animations": "11.2.14",
+        "@angular/common": "11.2.14",
+        "@angular/core": "11.2.14"
+      },
+      "peerDependenciesMeta": {
+        "@angular/animations": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@angular/platform-browser-dynamic": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-11.2.14.tgz",
+      "integrity": "sha512-TWTPdFs6iBBcp+/YMsgCRQwdHpWGq8KjeJDJ2tfatGgBD3Gqt2YaHOMST1zPW6RkrmupytTejuVqXzeaKWFxuw==",
+      "dependencies": {
+        "tslib": "^2.0.0"
+      },
+      "peerDependencies": {
+        "@angular/common": "11.2.14",
+        "@angular/compiler": "11.2.14",
+        "@angular/core": "11.2.14",
+        "@angular/platform-browser": "11.2.14"
+      }
+    },
+    "node_modules/@angular/platform-server": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-11.2.14.tgz",
+      "integrity": "sha512-VSJ4FSyMPVCE3EGfD4hIK1fZu+KFYi04uL4Co8vchzBQFpXPFABpCS/lGd7rOyvLnKRmUvl4NGS72gQdS00IUw==",
+      "dependencies": {
+        "domino": "^2.1.2",
+        "tslib": "^2.0.0",
+        "xhr2": "^0.2.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      },
+      "peerDependencies": {
+        "@angular/animations": "11.2.14",
+        "@angular/common": "11.2.14",
+        "@angular/compiler": "11.2.14",
+        "@angular/core": "11.2.14",
+        "@angular/platform-browser": "11.2.14",
+        "@angular/platform-browser-dynamic": "11.2.14"
+      }
+    },
+    "node_modules/@angular/router": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/router/-/router-11.2.14.tgz",
+      "integrity": "sha512-3aYBmj+zrEL9yf/ntIQxHIYaWShZOBKP3U07X2mX+TPMpGlvHDnR7L6bWhQVZwewzMMz7YVR16ldg50IFuAlfA==",
+      "dependencies": {
+        "tslib": "^2.0.0"
+      },
+      "peerDependencies": {
+        "@angular/common": "11.2.14",
+        "@angular/core": "11.2.14",
+        "@angular/platform-browser": "11.2.14",
+        "rxjs": "^6.5.3"
+      }
+    },
+    "node_modules/@assemblyscript/loader": {
+      "version": "0.10.1",
+      "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz",
+      "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==",
+      "dev": true
+    },
+    "node_modules/@babel/code-frame": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
+      "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
+      "dependencies": {
+        "@babel/highlight": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/compat-data": {
+      "version": "7.20.14",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz",
+      "integrity": "sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw==",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/core": {
+      "version": "7.20.12",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz",
+      "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==",
+      "dependencies": {
+        "@ampproject/remapping": "^2.1.0",
+        "@babel/code-frame": "^7.18.6",
+        "@babel/generator": "^7.20.7",
+        "@babel/helper-compilation-targets": "^7.20.7",
+        "@babel/helper-module-transforms": "^7.20.11",
+        "@babel/helpers": "^7.20.7",
+        "@babel/parser": "^7.20.7",
+        "@babel/template": "^7.20.7",
+        "@babel/traverse": "^7.20.12",
+        "@babel/types": "^7.20.7",
+        "convert-source-map": "^1.7.0",
+        "debug": "^4.1.0",
+        "gensync": "^1.0.0-beta.2",
+        "json5": "^2.2.2",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/babel"
+      }
+    },
+    "node_modules/@babel/core/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@babel/generator": {
+      "version": "7.20.14",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz",
+      "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==",
+      "dependencies": {
+        "@babel/types": "^7.20.7",
+        "@jridgewell/gen-mapping": "^0.3.2",
+        "jsesc": "^2.5.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
+      "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
+      "dependencies": {
+        "@jridgewell/set-array": "^1.0.1",
+        "@jridgewell/sourcemap-codec": "^1.4.10",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/helper-annotate-as-pure": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz",
+      "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz",
+      "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-explode-assignable-expression": "^7.18.6",
+        "@babel/types": "^7.18.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz",
+      "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==",
+      "dependencies": {
+        "@babel/compat-data": "^7.20.5",
+        "@babel/helper-validator-option": "^7.18.6",
+        "browserslist": "^4.21.3",
+        "lru-cache": "^5.1.1",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+      "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+      "dependencies": {
+        "yallist": "^3.0.2"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@babel/helper-compilation-targets/node_modules/yallist": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+      "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
+    },
+    "node_modules/@babel/helper-create-class-features-plugin": {
+      "version": "7.20.12",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.12.tgz",
+      "integrity": "sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.18.6",
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-function-name": "^7.19.0",
+        "@babel/helper-member-expression-to-functions": "^7.20.7",
+        "@babel/helper-optimise-call-expression": "^7.18.6",
+        "@babel/helper-replace-supers": "^7.20.7",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0",
+        "@babel/helper-split-export-declaration": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-create-regexp-features-plugin": {
+      "version": "7.20.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz",
+      "integrity": "sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.18.6",
+        "regexpu-core": "^5.2.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-define-polyfill-provider": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz",
+      "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-compilation-targets": "^7.17.7",
+        "@babel/helper-plugin-utils": "^7.16.7",
+        "debug": "^4.1.1",
+        "lodash.debounce": "^4.0.8",
+        "resolve": "^1.14.2",
+        "semver": "^6.1.2"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.4.0-0"
+      }
+    },
+    "node_modules/@babel/helper-define-polyfill-provider/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@babel/helper-environment-visitor": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
+      "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-explode-assignable-expression": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz",
+      "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-function-name": {
+      "version": "7.19.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
+      "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
+      "dependencies": {
+        "@babel/template": "^7.18.10",
+        "@babel/types": "^7.19.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-hoist-variables": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
+      "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
+      "dependencies": {
+        "@babel/types": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-member-expression-to-functions": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz",
+      "integrity": "sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.20.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-imports": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
+      "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
+      "dependencies": {
+        "@babel/types": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-module-transforms": {
+      "version": "7.20.11",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz",
+      "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==",
+      "dependencies": {
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-module-imports": "^7.18.6",
+        "@babel/helper-simple-access": "^7.20.2",
+        "@babel/helper-split-export-declaration": "^7.18.6",
+        "@babel/helper-validator-identifier": "^7.19.1",
+        "@babel/template": "^7.20.7",
+        "@babel/traverse": "^7.20.10",
+        "@babel/types": "^7.20.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-optimise-call-expression": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz",
+      "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-plugin-utils": {
+      "version": "7.20.2",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz",
+      "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-remap-async-to-generator": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz",
+      "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.18.6",
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-wrap-function": "^7.18.9",
+        "@babel/types": "^7.18.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/helper-replace-supers": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz",
+      "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-member-expression-to-functions": "^7.20.7",
+        "@babel/helper-optimise-call-expression": "^7.18.6",
+        "@babel/template": "^7.20.7",
+        "@babel/traverse": "^7.20.7",
+        "@babel/types": "^7.20.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-simple-access": {
+      "version": "7.20.2",
+      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
+      "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
+      "dependencies": {
+        "@babel/types": "^7.20.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-skip-transparent-expression-wrappers": {
+      "version": "7.20.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz",
+      "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/types": "^7.20.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-split-export-declaration": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
+      "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
+      "dependencies": {
+        "@babel/types": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-string-parser": {
+      "version": "7.19.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
+      "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.19.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
+      "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-option": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
+      "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-wrap-function": {
+      "version": "7.20.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz",
+      "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-function-name": "^7.19.0",
+        "@babel/template": "^7.18.10",
+        "@babel/traverse": "^7.20.5",
+        "@babel/types": "^7.20.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helpers": {
+      "version": "7.20.13",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz",
+      "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==",
+      "dependencies": {
+        "@babel/template": "^7.20.7",
+        "@babel/traverse": "^7.20.13",
+        "@babel/types": "^7.20.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/highlight": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
+      "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.18.6",
+        "chalk": "^2.0.0",
+        "js-tokens": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/parser": {
+      "version": "7.20.15",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz",
+      "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg==",
+      "bin": {
+        "parser": "bin/babel-parser.js"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz",
+      "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz",
+      "integrity": "sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0",
+        "@babel/plugin-proposal-optional-chaining": "^7.20.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.13.0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-async-generator-functions": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz",
+      "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/helper-remap-async-to-generator": "^7.18.9",
+        "@babel/plugin-syntax-async-generators": "^7.8.4"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-class-properties": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz",
+      "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-create-class-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-class-static-block": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.20.7.tgz",
+      "integrity": "sha512-AveGOoi9DAjUYYuUAG//Ig69GlazLnoyzMw68VCDux+c1tsnnH/OkYcpz/5xzMkEFC6UxjR5Gw1c+iY2wOGVeQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-create-class-features-plugin": "^7.20.7",
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/plugin-syntax-class-static-block": "^7.14.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.12.0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-dynamic-import": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz",
+      "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/plugin-syntax-dynamic-import": "^7.8.3"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-export-namespace-from": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz",
+      "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.9",
+        "@babel/plugin-syntax-export-namespace-from": "^7.8.3"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-json-strings": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz",
+      "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/plugin-syntax-json-strings": "^7.8.3"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-logical-assignment-operators": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz",
+      "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz",
+      "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-numeric-separator": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz",
+      "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/plugin-syntax-numeric-separator": "^7.10.4"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-object-rest-spread": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz",
+      "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/compat-data": "^7.20.5",
+        "@babel/helper-compilation-targets": "^7.20.7",
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
+        "@babel/plugin-transform-parameters": "^7.20.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-optional-catch-binding": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz",
+      "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/plugin-syntax-optional-catch-binding": "^7.8.3"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-optional-chaining": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.20.7.tgz",
+      "integrity": "sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0",
+        "@babel/plugin-syntax-optional-chaining": "^7.8.3"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-private-methods": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz",
+      "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-create-class-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-private-property-in-object": {
+      "version": "7.20.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz",
+      "integrity": "sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.18.6",
+        "@babel/helper-create-class-features-plugin": "^7.20.5",
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/plugin-syntax-private-property-in-object": "^7.14.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-proposal-unicode-property-regex": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz",
+      "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-create-regexp-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-async-generators": {
+      "version": "7.8.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
+      "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-class-properties": {
+      "version": "7.12.13",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
+      "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.12.13"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-class-static-block": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz",
+      "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.14.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-dynamic-import": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz",
+      "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-export-namespace-from": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz",
+      "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.3"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-import-assertions": {
+      "version": "7.20.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz",
+      "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.19.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-json-strings": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
+      "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-logical-assignment-operators": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz",
+      "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz",
+      "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-numeric-separator": {
+      "version": "7.10.4",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz",
+      "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.10.4"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-object-rest-spread": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz",
+      "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-optional-catch-binding": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz",
+      "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-optional-chaining": {
+      "version": "7.8.3",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz",
+      "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.8.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-private-property-in-object": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz",
+      "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.14.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-syntax-top-level-await": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz",
+      "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.14.5"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-arrow-functions": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz",
+      "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.20.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-async-to-generator": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz",
+      "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-module-imports": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/helper-remap-async-to-generator": "^7.18.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-block-scoped-functions": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz",
+      "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-block-scoping": {
+      "version": "7.20.15",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.15.tgz",
+      "integrity": "sha512-Vv4DMZ6MiNOhu/LdaZsT/bsLRxgL94d269Mv4R/9sp6+Mp++X/JqypZYypJXLlM4mlL352/Egzbzr98iABH1CA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.20.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-classes": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.7.tgz",
+      "integrity": "sha512-LWYbsiXTPKl+oBlXUGlwNlJZetXD5Am+CyBdqhPsDVjM9Jc8jwBJFrKhHf900Kfk2eZG1y9MAG3UNajol7A4VQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-annotate-as-pure": "^7.18.6",
+        "@babel/helper-compilation-targets": "^7.20.7",
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-function-name": "^7.19.0",
+        "@babel/helper-optimise-call-expression": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/helper-replace-supers": "^7.20.7",
+        "@babel/helper-split-export-declaration": "^7.18.6",
+        "globals": "^11.1.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-computed-properties": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz",
+      "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/template": "^7.20.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-destructuring": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz",
+      "integrity": "sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.20.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-dotall-regex": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz",
+      "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-create-regexp-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-duplicate-keys": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz",
+      "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-exponentiation-operator": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz",
+      "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-for-of": {
+      "version": "7.18.8",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz",
+      "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-function-name": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz",
+      "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-compilation-targets": "^7.18.9",
+        "@babel/helper-function-name": "^7.18.9",
+        "@babel/helper-plugin-utils": "^7.18.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-literals": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz",
+      "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-member-expression-literals": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz",
+      "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-modules-amd": {
+      "version": "7.20.11",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz",
+      "integrity": "sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-module-transforms": "^7.20.11",
+        "@babel/helper-plugin-utils": "^7.20.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-modules-commonjs": {
+      "version": "7.20.11",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.11.tgz",
+      "integrity": "sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-module-transforms": "^7.20.11",
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/helper-simple-access": "^7.20.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-modules-systemjs": {
+      "version": "7.20.11",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz",
+      "integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-hoist-variables": "^7.18.6",
+        "@babel/helper-module-transforms": "^7.20.11",
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/helper-validator-identifier": "^7.19.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-modules-umd": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz",
+      "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-module-transforms": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-named-capturing-groups-regex": {
+      "version": "7.20.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz",
+      "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-create-regexp-features-plugin": "^7.20.5",
+        "@babel/helper-plugin-utils": "^7.20.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-new-target": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz",
+      "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-object-super": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz",
+      "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/helper-replace-supers": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-parameters": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz",
+      "integrity": "sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.20.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-property-literals": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz",
+      "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-regenerator": {
+      "version": "7.20.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz",
+      "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "regenerator-transform": "^0.15.1"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-reserved-words": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz",
+      "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-runtime": {
+      "version": "7.19.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz",
+      "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-module-imports": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.19.0",
+        "babel-plugin-polyfill-corejs2": "^0.3.3",
+        "babel-plugin-polyfill-corejs3": "^0.6.0",
+        "babel-plugin-polyfill-regenerator": "^0.4.1",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-runtime/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@babel/plugin-transform-shorthand-properties": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz",
+      "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-spread": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz",
+      "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-sticky-regex": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz",
+      "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-template-literals": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz",
+      "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-typeof-symbol": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz",
+      "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-unicode-escapes": {
+      "version": "7.18.10",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz",
+      "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.18.9"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/plugin-transform-unicode-regex": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz",
+      "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-create-regexp-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/preset-env": {
+      "version": "7.20.2",
+      "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz",
+      "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/compat-data": "^7.20.1",
+        "@babel/helper-compilation-targets": "^7.20.0",
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/helper-validator-option": "^7.18.6",
+        "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6",
+        "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9",
+        "@babel/plugin-proposal-async-generator-functions": "^7.20.1",
+        "@babel/plugin-proposal-class-properties": "^7.18.6",
+        "@babel/plugin-proposal-class-static-block": "^7.18.6",
+        "@babel/plugin-proposal-dynamic-import": "^7.18.6",
+        "@babel/plugin-proposal-export-namespace-from": "^7.18.9",
+        "@babel/plugin-proposal-json-strings": "^7.18.6",
+        "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9",
+        "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
+        "@babel/plugin-proposal-numeric-separator": "^7.18.6",
+        "@babel/plugin-proposal-object-rest-spread": "^7.20.2",
+        "@babel/plugin-proposal-optional-catch-binding": "^7.18.6",
+        "@babel/plugin-proposal-optional-chaining": "^7.18.9",
+        "@babel/plugin-proposal-private-methods": "^7.18.6",
+        "@babel/plugin-proposal-private-property-in-object": "^7.18.6",
+        "@babel/plugin-proposal-unicode-property-regex": "^7.18.6",
+        "@babel/plugin-syntax-async-generators": "^7.8.4",
+        "@babel/plugin-syntax-class-properties": "^7.12.13",
+        "@babel/plugin-syntax-class-static-block": "^7.14.5",
+        "@babel/plugin-syntax-dynamic-import": "^7.8.3",
+        "@babel/plugin-syntax-export-namespace-from": "^7.8.3",
+        "@babel/plugin-syntax-import-assertions": "^7.20.0",
+        "@babel/plugin-syntax-json-strings": "^7.8.3",
+        "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
+        "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
+        "@babel/plugin-syntax-numeric-separator": "^7.10.4",
+        "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
+        "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
+        "@babel/plugin-syntax-optional-chaining": "^7.8.3",
+        "@babel/plugin-syntax-private-property-in-object": "^7.14.5",
+        "@babel/plugin-syntax-top-level-await": "^7.14.5",
+        "@babel/plugin-transform-arrow-functions": "^7.18.6",
+        "@babel/plugin-transform-async-to-generator": "^7.18.6",
+        "@babel/plugin-transform-block-scoped-functions": "^7.18.6",
+        "@babel/plugin-transform-block-scoping": "^7.20.2",
+        "@babel/plugin-transform-classes": "^7.20.2",
+        "@babel/plugin-transform-computed-properties": "^7.18.9",
+        "@babel/plugin-transform-destructuring": "^7.20.2",
+        "@babel/plugin-transform-dotall-regex": "^7.18.6",
+        "@babel/plugin-transform-duplicate-keys": "^7.18.9",
+        "@babel/plugin-transform-exponentiation-operator": "^7.18.6",
+        "@babel/plugin-transform-for-of": "^7.18.8",
+        "@babel/plugin-transform-function-name": "^7.18.9",
+        "@babel/plugin-transform-literals": "^7.18.9",
+        "@babel/plugin-transform-member-expression-literals": "^7.18.6",
+        "@babel/plugin-transform-modules-amd": "^7.19.6",
+        "@babel/plugin-transform-modules-commonjs": "^7.19.6",
+        "@babel/plugin-transform-modules-systemjs": "^7.19.6",
+        "@babel/plugin-transform-modules-umd": "^7.18.6",
+        "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1",
+        "@babel/plugin-transform-new-target": "^7.18.6",
+        "@babel/plugin-transform-object-super": "^7.18.6",
+        "@babel/plugin-transform-parameters": "^7.20.1",
+        "@babel/plugin-transform-property-literals": "^7.18.6",
+        "@babel/plugin-transform-regenerator": "^7.18.6",
+        "@babel/plugin-transform-reserved-words": "^7.18.6",
+        "@babel/plugin-transform-shorthand-properties": "^7.18.6",
+        "@babel/plugin-transform-spread": "^7.19.0",
+        "@babel/plugin-transform-sticky-regex": "^7.18.6",
+        "@babel/plugin-transform-template-literals": "^7.18.9",
+        "@babel/plugin-transform-typeof-symbol": "^7.18.9",
+        "@babel/plugin-transform-unicode-escapes": "^7.18.10",
+        "@babel/plugin-transform-unicode-regex": "^7.18.6",
+        "@babel/preset-modules": "^0.1.5",
+        "@babel/types": "^7.20.2",
+        "babel-plugin-polyfill-corejs2": "^0.3.3",
+        "babel-plugin-polyfill-corejs3": "^0.6.0",
+        "babel-plugin-polyfill-regenerator": "^0.4.1",
+        "core-js-compat": "^3.25.1",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/preset-env/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/@babel/preset-modules": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz",
+      "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.0.0",
+        "@babel/plugin-proposal-unicode-property-regex": "^7.4.4",
+        "@babel/plugin-transform-dotall-regex": "^7.4.4",
+        "@babel/types": "^7.4.4",
+        "esutils": "^2.0.2"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/@babel/regjsgen": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz",
+      "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==",
+      "dev": true
+    },
+    "node_modules/@babel/runtime": {
+      "version": "7.20.13",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz",
+      "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==",
+      "dev": true,
+      "dependencies": {
+        "regenerator-runtime": "^0.13.11"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/template": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
+      "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
+      "dependencies": {
+        "@babel/code-frame": "^7.18.6",
+        "@babel/parser": "^7.20.7",
+        "@babel/types": "^7.20.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/traverse": {
+      "version": "7.20.13",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz",
+      "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==",
+      "dependencies": {
+        "@babel/code-frame": "^7.18.6",
+        "@babel/generator": "^7.20.7",
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-function-name": "^7.19.0",
+        "@babel/helper-hoist-variables": "^7.18.6",
+        "@babel/helper-split-export-declaration": "^7.18.6",
+        "@babel/parser": "^7.20.13",
+        "@babel/types": "^7.20.7",
+        "debug": "^4.1.0",
+        "globals": "^11.1.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/types": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz",
+      "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==",
+      "dependencies": {
+        "@babel/helper-string-parser": "^7.19.4",
+        "@babel/helper-validator-identifier": "^7.19.1",
+        "to-fast-properties": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@discoveryjs/json-ext": {
+      "version": "0.5.7",
+      "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
+      "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/@esbuild/android-arm": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.8.tgz",
+      "integrity": "sha512-0/rb91GYKhrtbeglJXOhAv9RuYimgI8h623TplY2X+vA4EXnk3Zj1fXZreJ0J3OJJu1bwmb0W7g+2cT/d8/l/w==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/android-arm64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.8.tgz",
+      "integrity": "sha512-oa/N5j6v1svZQs7EIRPqR8f+Bf8g6HBDjD/xHC02radE/NjKHK7oQmtmLxPs1iVwYyvE+Kolo6lbpfEQ9xnhxQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/android-x64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.8.tgz",
+      "integrity": "sha512-bTliMLqD7pTOoPg4zZkXqCDuzIUguEWLpeqkNfC41ODBHwoUgZ2w5JBeYimv4oP6TDVocoYmEhZrCLQTrH89bg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/darwin-arm64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.8.tgz",
+      "integrity": "sha512-ghAbV3ia2zybEefXRRm7+lx8J/rnupZT0gp9CaGy/3iolEXkJ6LYRq4IpQVI9zR97ID80KJVoUlo3LSeA/sMAg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/darwin-x64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.8.tgz",
+      "integrity": "sha512-n5WOpyvZ9TIdv2V1K3/iIkkJeKmUpKaCTdun9buhGRWfH//osmUjlv4Z5mmWdPWind/VGcVxTHtLfLCOohsOXw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/freebsd-arm64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.8.tgz",
+      "integrity": "sha512-a/SATTaOhPIPFWvHZDoZYgxaZRVHn0/LX1fHLGfZ6C13JqFUZ3K6SMD6/HCtwOQ8HnsNaEeokdiDSFLuizqv5A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/freebsd-x64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.8.tgz",
+      "integrity": "sha512-xpFJb08dfXr5+rZc4E+ooZmayBW6R3q59daCpKZ/cDU96/kvDM+vkYzNeTJCGd8rtO6fHWMq5Rcv/1cY6p6/0Q==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-arm": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.8.tgz",
+      "integrity": "sha512-6Ij8gfuGszcEwZpi5jQIJCVIACLS8Tz2chnEBfYjlmMzVsfqBP1iGmHQPp7JSnZg5xxK9tjCc+pJ2WtAmPRFVA==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-arm64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.8.tgz",
+      "integrity": "sha512-v3iwDQuDljLTxpsqQDl3fl/yihjPAyOguxuloON9kFHYwopeJEf1BkDXODzYyXEI19gisEsQlG1bM65YqKSIww==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-ia32": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.8.tgz",
+      "integrity": "sha512-8svILYKhE5XetuFk/B6raFYIyIqydQi+GngEXJgdPdI7OMKUbSd7uzR02wSY4kb53xBrClLkhH4Xs8P61Q2BaA==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-loong64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.8.tgz",
+      "integrity": "sha512-B6FyMeRJeV0NpyEOYlm5qtQfxbdlgmiGdD+QsipzKfFky0K5HW5Td6dyK3L3ypu1eY4kOmo7wW0o94SBqlqBSA==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-mips64el": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.8.tgz",
+      "integrity": "sha512-CCb67RKahNobjm/eeEqeD/oJfJlrWyw29fgiyB6vcgyq97YAf3gCOuP6qMShYSPXgnlZe/i4a8WFHBw6N8bYAA==",
+      "cpu": [
+        "mips64el"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-ppc64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.8.tgz",
+      "integrity": "sha512-bytLJOi55y55+mGSdgwZ5qBm0K9WOCh0rx+vavVPx+gqLLhxtSFU0XbeYy/dsAAD6xECGEv4IQeFILaSS2auXw==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-riscv64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.8.tgz",
+      "integrity": "sha512-2YpRyQJmKVBEHSBLa8kBAtbhucaclb6ex4wchfY0Tj3Kg39kpjeJ9vhRU7x4mUpq8ISLXRXH1L0dBYjAeqzZAw==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-s390x": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.8.tgz",
+      "integrity": "sha512-QgbNY/V3IFXvNf11SS6exkpVcX0LJcob+0RWCgV9OiDAmVElnxciHIisoSix9uzYzScPmS6dJFbZULdSAEkQVw==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-x64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.8.tgz",
+      "integrity": "sha512-mM/9S0SbAFDBc4OPoyP6SEOo5324LpUxdpeIUUSrSTOfhHU9hEfqRngmKgqILqwx/0DVJBzeNW7HmLEWp9vcOA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/netbsd-x64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.8.tgz",
+      "integrity": "sha512-eKUYcWaWTaYr9zbj8GertdVtlt1DTS1gNBWov+iQfWuWyuu59YN6gSEJvFzC5ESJ4kMcKR0uqWThKUn5o8We6Q==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/openbsd-x64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.8.tgz",
+      "integrity": "sha512-Vc9J4dXOboDyMXKD0eCeW0SIeEzr8K9oTHJU+Ci1mZc5njPfhKAqkRt3B/fUNU7dP+mRyralPu8QUkiaQn7iIg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/sunos-x64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.8.tgz",
+      "integrity": "sha512-0xvOTNuPXI7ft1LYUgiaXtpCEjp90RuBBYovdd2lqAFxje4sEucurg30M1WIm03+3jxByd3mfo+VUmPtRSVuOw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/win32-arm64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.8.tgz",
+      "integrity": "sha512-G0JQwUI5WdEFEnYNKzklxtBheCPkuDdu1YrtRrjuQv30WsYbkkoixKxLLv8qhJmNI+ATEWquZe/N0d0rpr55Mg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/win32-ia32": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.8.tgz",
+      "integrity": "sha512-Fqy63515xl20OHGFykjJsMnoIWS+38fqfg88ClvPXyDbLtgXal2DTlhb1TfTX34qWi3u4I7Cq563QcHpqgLx8w==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/win32-x64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.8.tgz",
+      "integrity": "sha512-1iuezdyDNngPnz8rLRDO2C/ZZ/emJLb72OsZeqQ6gL6Avko/XCXZw+NuxBSNhBAP13Hie418V7VMt9et1FMvpg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@istanbuljs/load-nyc-config": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
+      "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
+      "dev": true,
+      "dependencies": {
+        "camelcase": "^5.3.1",
+        "find-up": "^4.1.0",
+        "get-package-type": "^0.1.0",
+        "js-yaml": "^3.13.1",
+        "resolve-from": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@istanbuljs/schema": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
+      "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/@jridgewell/gen-mapping": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
+      "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
+      "dependencies": {
+        "@jridgewell/set-array": "^1.0.0",
+        "@jridgewell/sourcemap-codec": "^1.4.10"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/resolve-uri": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+      "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/set-array": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz",
+      "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==",
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/source-map": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
+      "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/gen-mapping": "^0.3.0",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      }
+    },
+    "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
+      "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/set-array": "^1.0.1",
+        "@jridgewell/sourcemap-codec": "^1.4.10",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.4.14",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
+    },
+    "node_modules/@jridgewell/trace-mapping": {
+      "version": "0.3.17",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
+      "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
+      "dependencies": {
+        "@jridgewell/resolve-uri": "3.1.0",
+        "@jridgewell/sourcemap-codec": "1.4.14"
+      }
+    },
+    "node_modules/@leichtgewicht/ip-codec": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz",
+      "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
+      "dev": true
+    },
+    "node_modules/@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dev": true,
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "dev": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dev": true,
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@npmcli/ci-detect": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/@npmcli/ci-detect/-/ci-detect-1.4.0.tgz",
+      "integrity": "sha512-3BGrt6FLjqM6br5AhWRKTr3u5GIVkjRYeAFrMp3HjnfICrg4xOrVRwFavKT6tsp++bq5dluL5t8ME/Nha/6c1Q==",
+      "dev": true
+    },
+    "node_modules/@npmcli/fs": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz",
+      "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==",
+      "dev": true,
+      "dependencies": {
+        "semver": "^7.3.5"
+      },
+      "engines": {
+        "node": "^14.17.0 || ^16.13.0 || >=18.0.0"
+      }
+    },
+    "node_modules/@npmcli/fs/node_modules/semver": {
+      "version": "7.3.8",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@npmcli/git": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-2.1.0.tgz",
+      "integrity": "sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw==",
+      "dev": true,
+      "dependencies": {
+        "@npmcli/promise-spawn": "^1.3.2",
+        "lru-cache": "^6.0.0",
+        "mkdirp": "^1.0.4",
+        "npm-pick-manifest": "^6.1.1",
+        "promise-inflight": "^1.0.1",
+        "promise-retry": "^2.0.1",
+        "semver": "^7.3.5",
+        "which": "^2.0.2"
+      }
+    },
+    "node_modules/@npmcli/git/node_modules/err-code": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz",
+      "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==",
+      "dev": true
+    },
+    "node_modules/@npmcli/git/node_modules/hosted-git-info": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
+      "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@npmcli/git/node_modules/mkdirp": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+      "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+      "dev": true,
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@npmcli/git/node_modules/npm-package-arg": {
+      "version": "8.1.5",
+      "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.5.tgz",
+      "integrity": "sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q==",
+      "dev": true,
+      "dependencies": {
+        "hosted-git-info": "^4.0.1",
+        "semver": "^7.3.4",
+        "validate-npm-package-name": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@npmcli/git/node_modules/npm-pick-manifest": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz",
+      "integrity": "sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA==",
+      "dev": true,
+      "dependencies": {
+        "npm-install-checks": "^4.0.0",
+        "npm-normalize-package-bin": "^1.0.1",
+        "npm-package-arg": "^8.1.2",
+        "semver": "^7.3.4"
+      }
+    },
+    "node_modules/@npmcli/git/node_modules/promise-retry": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz",
+      "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==",
+      "dev": true,
+      "dependencies": {
+        "err-code": "^2.0.2",
+        "retry": "^0.12.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@npmcli/git/node_modules/retry": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
+      "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=",
+      "dev": true,
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/@npmcli/git/node_modules/semver": {
+      "version": "7.3.7",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+      "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@npmcli/installed-package-contents": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz",
+      "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==",
+      "dev": true,
+      "dependencies": {
+        "npm-bundled": "^1.1.1",
+        "npm-normalize-package-bin": "^1.0.1"
+      },
+      "bin": {
+        "installed-package-contents": "index.js"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/@npmcli/move-file": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz",
+      "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==",
+      "dev": true,
+      "dependencies": {
+        "mkdirp": "^1.0.4",
+        "rimraf": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@npmcli/move-file/node_modules/mkdirp": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+      "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+      "dev": true,
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@npmcli/node-gyp": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz",
+      "integrity": "sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA==",
+      "dev": true
+    },
+    "node_modules/@npmcli/promise-spawn": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz",
+      "integrity": "sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg==",
+      "dev": true,
+      "dependencies": {
+        "infer-owner": "^1.0.4"
+      }
+    },
+    "node_modules/@npmcli/run-script": {
+      "version": "1.8.6",
+      "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.6.tgz",
+      "integrity": "sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g==",
+      "dev": true,
+      "dependencies": {
+        "@npmcli/node-gyp": "^1.0.2",
+        "@npmcli/promise-spawn": "^1.3.2",
+        "node-gyp": "^7.1.0",
+        "read-package-json-fast": "^2.0.1"
+      }
+    },
+    "node_modules/@npmcli/run-script/node_modules/read-package-json-fast": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz",
+      "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==",
+      "dev": true,
+      "dependencies": {
+        "json-parse-even-better-errors": "^2.3.0",
+        "npm-normalize-package-bin": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@polka/url": {
+      "version": "1.0.0-next.21",
+      "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz",
+      "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==",
+      "dev": true
+    },
+    "node_modules/@schematics/angular": {
+      "version": "11.2.19",
+      "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-11.2.19.tgz",
+      "integrity": "sha512-cZys7nRo/CI81EtPu4VJiAyv53gPfIfLteykhrTQpAp9AZK9UuRHauiJq7BhHRAUEc3z148xjSQgMvEu7/vAuA==",
+      "dev": true,
+      "dependencies": {
+        "@angular-devkit/core": "11.2.19",
+        "@angular-devkit/schematics": "11.2.19",
+        "jsonc-parser": "3.0.0"
+      },
+      "engines": {
+        "node": ">= 10.13.0",
+        "npm": "^6.11.0 || ^7.5.6",
+        "yarn": ">= 1.13.0"
+      }
+    },
+    "node_modules/@schematics/update": {
+      "version": "0.1102.19",
+      "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.1102.19.tgz",
+      "integrity": "sha512-NdWzL6n/ZEgnposWdAPo8PTOn+8Baf/J9isjF+QOUUMbpZY/+QfLpej7eDAlcQ2Begiz/selMsnod70r9PYZUg==",
+      "deprecated": "This was an internal-only Angular package up through Angular v11 which is no longer used or maintained. Upgrade Angular to v12+ to remove this dependency.",
+      "dev": true,
+      "dependencies": {
+        "@angular-devkit/core": "11.2.19",
+        "@angular-devkit/schematics": "11.2.19",
+        "@yarnpkg/lockfile": "1.1.0",
+        "ini": "2.0.0",
+        "npm-package-arg": "^8.0.0",
+        "pacote": "11.2.4",
+        "semver": "7.3.4",
+        "semver-intersect": "1.4.0"
+      },
+      "engines": {
+        "node": ">= 10.13.0",
+        "npm": "^6.11.0 || ^7.5.6",
+        "yarn": ">= 1.13.0"
+      }
+    },
+    "node_modules/@schematics/update/node_modules/semver": {
+      "version": "7.3.4",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
+      "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@tootallnate/once": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
+      "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/@types/body-parser": {
+      "version": "1.19.2",
+      "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
+      "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==",
+      "dev": true,
+      "dependencies": {
+        "@types/connect": "*",
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/bonjour": {
+      "version": "3.5.10",
+      "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz",
+      "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/connect": {
+      "version": "3.4.35",
+      "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
+      "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/connect-history-api-fallback": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz",
+      "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==",
+      "dev": true,
+      "dependencies": {
+        "@types/express-serve-static-core": "*",
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/eslint": {
+      "version": "8.21.0",
+      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.0.tgz",
+      "integrity": "sha512-35EhHNOXgxnUgh4XCJsGhE7zdlDhYDN/aMG6UbkByCFFNgQ7b3U+uVoqBpicFydR8JEfgdjCF7SJ7MiJfzuiTA==",
+      "dev": true,
+      "dependencies": {
+        "@types/estree": "*",
+        "@types/json-schema": "*"
+      }
+    },
+    "node_modules/@types/eslint-scope": {
+      "version": "3.7.4",
+      "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz",
+      "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==",
+      "dev": true,
+      "dependencies": {
+        "@types/eslint": "*",
+        "@types/estree": "*"
+      }
+    },
+    "node_modules/@types/estree": {
+      "version": "0.0.51",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz",
+      "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==",
+      "dev": true
+    },
+    "node_modules/@types/express": {
+      "version": "4.17.17",
+      "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz",
+      "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==",
+      "dev": true,
+      "dependencies": {
+        "@types/body-parser": "*",
+        "@types/express-serve-static-core": "^4.17.33",
+        "@types/qs": "*",
+        "@types/serve-static": "*"
+      }
+    },
+    "node_modules/@types/express-serve-static-core": {
+      "version": "4.17.33",
+      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz",
+      "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*",
+        "@types/qs": "*",
+        "@types/range-parser": "*"
+      }
+    },
+    "node_modules/@types/http-proxy": {
+      "version": "1.17.10",
+      "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.10.tgz",
+      "integrity": "sha512-Qs5aULi+zV1bwKAg5z1PWnDXWmsn+LxIvUGv6E2+OOMYhclZMO+OXd9pYVf2gLykf2I7IV2u7oTHwChPNsvJ7g==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/json-schema": {
+      "version": "7.0.11",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
+      "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
+      "dev": true
+    },
+    "node_modules/@types/mime": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
+      "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==",
+      "dev": true
+    },
+    "node_modules/@types/moment-timezone": {
+      "version": "0.5.30",
+      "resolved": "https://registry.npmjs.org/@types/moment-timezone/-/moment-timezone-0.5.30.tgz",
+      "integrity": "sha512-aDVfCsjYnAQaV/E9Qc24C5Njx1CoDjXsEgkxtp9NyXDpYu4CCbmclb6QhWloS9UTU/8YROUEEdEkWI0D7DxnKg==",
+      "deprecated": "This is a stub types definition. moment-timezone provides its own type definitions, so you do not need this installed.",
+      "dev": true,
+      "dependencies": {
+        "moment-timezone": "*"
+      }
+    },
+    "node_modules/@types/node": {
+      "version": "12.19.3",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.3.tgz",
+      "integrity": "sha512-8Jduo8wvvwDzEVJCOvS/G6sgilOLvvhn1eMmK3TW8/T217O7u1jdrK6ImKLv80tVryaPSVeKu6sjDEiFjd4/eg==",
+      "dev": true
+    },
+    "node_modules/@types/parse-json": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
+      "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
+      "dev": true
+    },
+    "node_modules/@types/qs": {
+      "version": "6.9.7",
+      "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
+      "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
+      "dev": true
+    },
+    "node_modules/@types/range-parser": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
+      "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
+      "dev": true
+    },
+    "node_modules/@types/retry": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
+      "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
+      "dev": true
+    },
+    "node_modules/@types/serve-index": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz",
+      "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==",
+      "dev": true,
+      "dependencies": {
+        "@types/express": "*"
+      }
+    },
+    "node_modules/@types/serve-static": {
+      "version": "1.15.1",
+      "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz",
+      "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/mime": "*",
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/sockjs": {
+      "version": "0.3.33",
+      "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz",
+      "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@types/ws": {
+      "version": "8.5.4",
+      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz",
+      "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*"
+      }
+    },
+    "node_modules/@webassemblyjs/ast": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
+      "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==",
+      "dev": true,
+      "dependencies": {
+        "@webassemblyjs/helper-numbers": "1.11.1",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.1"
+      }
+    },
+    "node_modules/@webassemblyjs/floating-point-hex-parser": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz",
+      "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==",
+      "dev": true
+    },
+    "node_modules/@webassemblyjs/helper-api-error": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz",
+      "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==",
+      "dev": true
+    },
+    "node_modules/@webassemblyjs/helper-buffer": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz",
+      "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==",
+      "dev": true
+    },
+    "node_modules/@webassemblyjs/helper-numbers": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz",
+      "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==",
+      "dev": true,
+      "dependencies": {
+        "@webassemblyjs/floating-point-hex-parser": "1.11.1",
+        "@webassemblyjs/helper-api-error": "1.11.1",
+        "@xtuc/long": "4.2.2"
+      }
+    },
+    "node_modules/@webassemblyjs/helper-wasm-bytecode": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz",
+      "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==",
+      "dev": true
+    },
+    "node_modules/@webassemblyjs/helper-wasm-section": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz",
+      "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==",
+      "dev": true,
+      "dependencies": {
+        "@webassemblyjs/ast": "1.11.1",
+        "@webassemblyjs/helper-buffer": "1.11.1",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
+        "@webassemblyjs/wasm-gen": "1.11.1"
+      }
+    },
+    "node_modules/@webassemblyjs/ieee754": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz",
+      "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==",
+      "dev": true,
+      "dependencies": {
+        "@xtuc/ieee754": "^1.2.0"
+      }
+    },
+    "node_modules/@webassemblyjs/leb128": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz",
+      "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==",
+      "dev": true,
+      "dependencies": {
+        "@xtuc/long": "4.2.2"
+      }
+    },
+    "node_modules/@webassemblyjs/utf8": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz",
+      "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==",
+      "dev": true
+    },
+    "node_modules/@webassemblyjs/wasm-edit": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz",
+      "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==",
+      "dev": true,
+      "dependencies": {
+        "@webassemblyjs/ast": "1.11.1",
+        "@webassemblyjs/helper-buffer": "1.11.1",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
+        "@webassemblyjs/helper-wasm-section": "1.11.1",
+        "@webassemblyjs/wasm-gen": "1.11.1",
+        "@webassemblyjs/wasm-opt": "1.11.1",
+        "@webassemblyjs/wasm-parser": "1.11.1",
+        "@webassemblyjs/wast-printer": "1.11.1"
+      }
+    },
+    "node_modules/@webassemblyjs/wasm-gen": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz",
+      "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==",
+      "dev": true,
+      "dependencies": {
+        "@webassemblyjs/ast": "1.11.1",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
+        "@webassemblyjs/ieee754": "1.11.1",
+        "@webassemblyjs/leb128": "1.11.1",
+        "@webassemblyjs/utf8": "1.11.1"
+      }
+    },
+    "node_modules/@webassemblyjs/wasm-opt": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz",
+      "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==",
+      "dev": true,
+      "dependencies": {
+        "@webassemblyjs/ast": "1.11.1",
+        "@webassemblyjs/helper-buffer": "1.11.1",
+        "@webassemblyjs/wasm-gen": "1.11.1",
+        "@webassemblyjs/wasm-parser": "1.11.1"
+      }
+    },
+    "node_modules/@webassemblyjs/wasm-parser": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz",
+      "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==",
+      "dev": true,
+      "dependencies": {
+        "@webassemblyjs/ast": "1.11.1",
+        "@webassemblyjs/helper-api-error": "1.11.1",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
+        "@webassemblyjs/ieee754": "1.11.1",
+        "@webassemblyjs/leb128": "1.11.1",
+        "@webassemblyjs/utf8": "1.11.1"
+      }
+    },
+    "node_modules/@webassemblyjs/wast-printer": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz",
+      "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==",
+      "dev": true,
+      "dependencies": {
+        "@webassemblyjs/ast": "1.11.1",
+        "@xtuc/long": "4.2.2"
+      }
+    },
+    "node_modules/@xtuc/ieee754": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
+      "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
+      "dev": true
+    },
+    "node_modules/@xtuc/long": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
+      "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
+      "dev": true
+    },
+    "node_modules/@yarnpkg/lockfile": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz",
+      "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==",
+      "dev": true
+    },
+    "node_modules/abab": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
+      "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==",
+      "dev": true
+    },
+    "node_modules/abbrev": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+      "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
+      "dev": true
+    },
+    "node_modules/accepts": {
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+      "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
+      "dev": true,
+      "dependencies": {
+        "mime-types": "~2.1.34",
+        "negotiator": "0.6.3"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/ace-builds": {
+      "version": "1.4.12",
+      "resolved": "https://registry.npmjs.org/ace-builds/-/ace-builds-1.4.12.tgz",
+      "integrity": "sha512-G+chJctFPiiLGvs3+/Mly3apXTcfgE45dT5yp12BcWZ1kUs+gm0qd3/fv4gsz6fVag4mM0moHVpjHDIgph6Psg=="
+    },
+    "node_modules/acorn": {
+      "version": "8.8.2",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
+      "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
+      "dev": true,
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-import-assertions": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz",
+      "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==",
+      "dev": true,
+      "peerDependencies": {
+        "acorn": "^8"
+      }
+    },
+    "node_modules/acorn-walk": {
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+      "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/adjust-sourcemap-loader": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz",
+      "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==",
+      "dev": true,
+      "dependencies": {
+        "loader-utils": "^2.0.0",
+        "regex-parser": "^2.2.11"
+      },
+      "engines": {
+        "node": ">=8.9"
+      }
+    },
+    "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
+      "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
+      "dev": true,
+      "dependencies": {
+        "big.js": "^5.2.2",
+        "emojis-list": "^3.0.0",
+        "json5": "^2.1.2"
+      },
+      "engines": {
+        "node": ">=8.9.0"
+      }
+    },
+    "node_modules/agent-base": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+      "dev": true,
+      "dependencies": {
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6.0.0"
+      }
+    },
+    "node_modules/agentkeepalive": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz",
+      "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==",
+      "dev": true,
+      "dependencies": {
+        "debug": "^4.1.0",
+        "depd": "^1.1.2",
+        "humanize-ms": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 8.0.0"
+      }
+    },
+    "node_modules/aggregate-error": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
+      "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==",
+      "dev": true,
+      "dependencies": {
+        "clean-stack": "^2.0.0",
+        "indent-string": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ajv": {
+      "version": "6.12.6",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
+      "dev": true,
+      "dependencies": {
+        "fast-deep-equal": "^3.1.1",
+        "fast-json-stable-stringify": "^2.0.0",
+        "json-schema-traverse": "^0.4.1",
+        "uri-js": "^4.2.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/ajv-formats": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
+      "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
+      "dev": true,
+      "dependencies": {
+        "ajv": "^8.0.0"
+      },
+      "peerDependencies": {
+        "ajv": "^8.0.0"
+      },
+      "peerDependenciesMeta": {
+        "ajv": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/ajv-formats/node_modules/ajv": {
+      "version": "8.12.0",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+      "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+      "dev": true,
+      "dependencies": {
+        "fast-deep-equal": "^3.1.1",
+        "json-schema-traverse": "^1.0.0",
+        "require-from-string": "^2.0.2",
+        "uri-js": "^4.2.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/ajv-formats/node_modules/json-schema-traverse": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+      "dev": true
+    },
+    "node_modules/ajv-keywords": {
+      "version": "3.5.2",
+      "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
+      "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
+      "dev": true,
+      "peerDependencies": {
+        "ajv": "^6.9.1"
+      }
+    },
+    "node_modules/ansi-colors": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
+      "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/ansi-escapes": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz",
+      "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==",
+      "dev": true,
+      "dependencies": {
+        "type-fest": "^0.11.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/ansi-html-community": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz",
+      "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==",
+      "dev": true,
+      "engines": [
+        "node >= 0.8.0"
+      ],
+      "bin": {
+        "ansi-html": "bin/ansi-html"
+      }
+    },
+    "node_modules/ansi-regex": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/anymatch": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/app-root-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz",
+      "integrity": "sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 6.0.0"
+      }
+    },
+    "node_modules/aproba": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+      "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
+      "dev": true
+    },
+    "node_modules/are-we-there-yet": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz",
+      "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==",
+      "dev": true,
+      "dependencies": {
+        "delegates": "^1.0.0",
+        "readable-stream": "^2.0.6"
+      }
+    },
+    "node_modules/arg": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
+      "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
+      "dev": true
+    },
+    "node_modules/argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dev": true,
+      "dependencies": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
+    "node_modules/aria-query": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz",
+      "integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=",
+      "dev": true,
+      "dependencies": {
+        "ast-types-flow": "0.0.7",
+        "commander": "^2.11.0"
+      }
+    },
+    "node_modules/array-flatten": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
+      "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==",
+      "dev": true
+    },
+    "node_modules/asn1": {
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+      "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+      "dev": true,
+      "dependencies": {
+        "safer-buffer": "~2.1.0"
+      }
+    },
+    "node_modules/assert-plus": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+      "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/ast-types-flow": {
+      "version": "0.0.7",
+      "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
+      "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=",
+      "dev": true
+    },
+    "node_modules/asynckit": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
+      "dev": true
+    },
+    "node_modules/autoprefixer": {
+      "version": "10.4.13",
+      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz",
+      "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+        }
+      ],
+      "dependencies": {
+        "browserslist": "^4.21.4",
+        "caniuse-lite": "^1.0.30001426",
+        "fraction.js": "^4.2.0",
+        "normalize-range": "^0.1.2",
+        "picocolors": "^1.0.0",
+        "postcss-value-parser": "^4.2.0"
+      },
+      "bin": {
+        "autoprefixer": "bin/autoprefixer"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      },
+      "peerDependencies": {
+        "postcss": "^8.1.0"
+      }
+    },
+    "node_modules/aws-sign2": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+      "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
+      "dev": true,
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/aws4": {
+      "version": "1.11.0",
+      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz",
+      "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
+      "dev": true
+    },
+    "node_modules/axobject-query": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz",
+      "integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==",
+      "dev": true,
+      "dependencies": {
+        "ast-types-flow": "0.0.7"
+      }
+    },
+    "node_modules/babel-plugin-istanbul": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz",
+      "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-plugin-utils": "^7.0.0",
+        "@istanbuljs/load-nyc-config": "^1.0.0",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-instrument": "^5.0.4",
+        "test-exclude": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/babel-plugin-polyfill-corejs2": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz",
+      "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==",
+      "dev": true,
+      "dependencies": {
+        "@babel/compat-data": "^7.17.7",
+        "@babel/helper-define-polyfill-provider": "^0.3.3",
+        "semver": "^6.1.1"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/babel-plugin-polyfill-corejs3": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz",
+      "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-define-polyfill-provider": "^0.3.3",
+        "core-js-compat": "^3.25.1"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/babel-plugin-polyfill-regenerator": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz",
+      "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==",
+      "dev": true,
+      "dependencies": {
+        "@babel/helper-define-polyfill-provider": "^0.3.3"
+      },
+      "peerDependencies": {
+        "@babel/core": "^7.0.0-0"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+    },
+    "node_modules/base64-js": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
+      "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==",
+      "dev": true
+    },
+    "node_modules/batch": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
+      "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==",
+      "dev": true
+    },
+    "node_modules/bcrypt-pbkdf": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
+      "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
+      "dev": true,
+      "dependencies": {
+        "tweetnacl": "^0.14.3"
+      }
+    },
+    "node_modules/big.js": {
+      "version": "5.2.2",
+      "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
+      "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
+      "dev": true,
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/binary-extensions": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
+      "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/bl": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+      "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+      "dev": true,
+      "dependencies": {
+        "buffer": "^5.5.0",
+        "inherits": "^2.0.4",
+        "readable-stream": "^3.4.0"
+      }
+    },
+    "node_modules/bl/node_modules/buffer": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+      "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.1.13"
+      }
+    },
+    "node_modules/bl/node_modules/readable-stream": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+      "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/body-parser": {
+      "version": "1.20.1",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
+      "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
+      "dev": true,
+      "dependencies": {
+        "bytes": "3.1.2",
+        "content-type": "~1.0.4",
+        "debug": "2.6.9",
+        "depd": "2.0.0",
+        "destroy": "1.2.0",
+        "http-errors": "2.0.0",
+        "iconv-lite": "0.4.24",
+        "on-finished": "2.4.1",
+        "qs": "6.11.0",
+        "raw-body": "2.5.1",
+        "type-is": "~1.6.18",
+        "unpipe": "1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8",
+        "npm": "1.2.8000 || >= 1.4.16"
+      }
+    },
+    "node_modules/body-parser/node_modules/bytes": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+      "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/body-parser/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/body-parser/node_modules/depd": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/body-parser/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true
+    },
+    "node_modules/bonjour-service": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.0.tgz",
+      "integrity": "sha512-LVRinRB3k1/K0XzZ2p58COnWvkQknIY6sf0zF2rpErvcJXpMBttEPQSxK+HEXSS9VmpZlDoDnQWv8ftJT20B0Q==",
+      "dev": true,
+      "dependencies": {
+        "array-flatten": "^2.1.2",
+        "dns-equal": "^1.0.0",
+        "fast-deep-equal": "^3.1.3",
+        "multicast-dns": "^7.2.5"
+      }
+    },
+    "node_modules/boolbase": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
+      "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
+      "dev": true
+    },
+    "node_modules/brace": {
+      "version": "0.11.1",
+      "resolved": "https://registry.npmjs.org/brace/-/brace-0.11.1.tgz",
+      "integrity": "sha1-SJb8ydVE7vRfS7dmDbMg07N5/lg="
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "dependencies": {
+        "fill-range": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/browserslist": {
+      "version": "4.21.5",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz",
+      "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        }
+      ],
+      "dependencies": {
+        "caniuse-lite": "^1.0.30001449",
+        "electron-to-chromium": "^1.4.284",
+        "node-releases": "^2.0.8",
+        "update-browserslist-db": "^1.0.10"
+      },
+      "bin": {
+        "browserslist": "cli.js"
+      },
+      "engines": {
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+      }
+    },
+    "node_modules/buffer-from": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
+      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+      "dev": true
+    },
+    "node_modules/builtin-modules": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
+      "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/builtins": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz",
+      "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=",
+      "dev": true
+    },
+    "node_modules/bytes": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
+      "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/cacache": {
+      "version": "15.0.5",
+      "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.0.5.tgz",
+      "integrity": "sha512-lloiL22n7sOjEEXdL8NAjTgv9a1u43xICE9/203qonkZUCj5X1UEWIdf2/Y0d6QcCtMzbKQyhrcDbdvlZTs/+A==",
+      "dev": true,
+      "dependencies": {
+        "@npmcli/move-file": "^1.0.1",
+        "chownr": "^2.0.0",
+        "fs-minipass": "^2.0.0",
+        "glob": "^7.1.4",
+        "infer-owner": "^1.0.4",
+        "lru-cache": "^6.0.0",
+        "minipass": "^3.1.1",
+        "minipass-collect": "^1.0.2",
+        "minipass-flush": "^1.0.5",
+        "minipass-pipeline": "^1.2.2",
+        "mkdirp": "^1.0.3",
+        "p-map": "^4.0.0",
+        "promise-inflight": "^1.0.1",
+        "rimraf": "^3.0.2",
+        "ssri": "^8.0.0",
+        "tar": "^6.0.2",
+        "unique-filename": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/cacache/node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "dev": true,
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/cacache/node_modules/mkdirp": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+      "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+      "dev": true,
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/call-bind": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+      "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+      "dev": true,
+      "dependencies": {
+        "function-bind": "^1.1.1",
+        "get-intrinsic": "^1.0.2"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/camelcase": {
+      "version": "5.3.1",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001451",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001451.tgz",
+      "integrity": "sha512-XY7UbUpGRatZzoRft//5xOa69/1iGJRBlrieH6QYrkKLIFn3m7OVEJ81dSrKoy2BnKsdbX5cLrOispZNYo9v2w==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        }
+      ]
+    },
+    "node_modules/canonical-path": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/canonical-path/-/canonical-path-1.0.0.tgz",
+      "integrity": "sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg=="
+    },
+    "node_modules/caseless": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
+      "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
+      "dev": true
+    },
+    "node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/chardet": {
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
+      "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
+      "dev": true
+    },
+    "node_modules/chokidar": {
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+      "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "dependencies": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
+      },
+      "engines": {
+        "node": ">= 8.10.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/chownr": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+      "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/chrome-trace-event": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
+      "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.0"
+      }
+    },
+    "node_modules/clean-stack": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
+      "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/cli-cursor": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
+      "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
+      "dev": true,
+      "dependencies": {
+        "restore-cursor": "^3.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/cli-spinners": {
+      "version": "2.6.1",
+      "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz",
+      "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/cli-width": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz",
+      "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/cliui": {
+      "version": "7.0.4",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+      "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+      "dependencies": {
+        "string-width": "^4.2.0",
+        "strip-ansi": "^6.0.0",
+        "wrap-ansi": "^7.0.0"
+      }
+    },
+    "node_modules/clone": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+      "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/clone-deep": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
+      "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
+      "dev": true,
+      "dependencies": {
+        "is-plain-object": "^2.0.4",
+        "kind-of": "^6.0.2",
+        "shallow-clone": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/code-point-at": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+      "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/codelyzer": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-6.0.2.tgz",
+      "integrity": "sha512-v3+E0Ucu2xWJMOJ2fA/q9pDT/hlxHftHGPUay1/1cTgyPV5JTHFdO9hqo837Sx2s9vKBMTt5gO+lhF95PO6J+g==",
+      "dev": true,
+      "dependencies": {
+        "@angular/compiler": "9.0.0",
+        "@angular/core": "9.0.0",
+        "app-root-path": "^3.0.0",
+        "aria-query": "^3.0.0",
+        "axobject-query": "2.0.2",
+        "css-selector-tokenizer": "^0.7.1",
+        "cssauron": "^1.4.0",
+        "damerau-levenshtein": "^1.0.4",
+        "rxjs": "^6.5.3",
+        "semver-dsl": "^1.0.1",
+        "source-map": "^0.5.7",
+        "sprintf-js": "^1.1.2",
+        "tslib": "^1.10.0",
+        "zone.js": "~0.10.3"
+      },
+      "peerDependencies": {
+        "@angular/compiler": ">=2.3.1 <13.0.0 || ^12.0.0-next || ^12.1.0-next || ^12.2.0-next",
+        "@angular/core": ">=2.3.1 <13.0.0 || ^12.0.0-next || ^12.1.0-next || ^12.2.0-next",
+        "tslint": "^5.0.0 || ^6.0.0"
+      }
+    },
+    "node_modules/codelyzer/node_modules/@angular/compiler": {
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.0.0.tgz",
+      "integrity": "sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ==",
+      "dev": true,
+      "peerDependencies": {
+        "tslib": "^1.10.0"
+      }
+    },
+    "node_modules/codelyzer/node_modules/@angular/core": {
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.0.0.tgz",
+      "integrity": "sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w==",
+      "dev": true,
+      "peerDependencies": {
+        "rxjs": "^6.5.3",
+        "tslib": "^1.10.0",
+        "zone.js": "~0.10.2"
+      }
+    },
+    "node_modules/codelyzer/node_modules/sprintf-js": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
+      "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==",
+      "dev": true
+    },
+    "node_modules/codelyzer/node_modules/tslib": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+      "dev": true
+    },
+    "node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
+    },
+    "node_modules/colorette": {
+      "version": "2.0.19",
+      "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
+      "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
+      "dev": true
+    },
+    "node_modules/combined-stream": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+      "dev": true,
+      "dependencies": {
+        "delayed-stream": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/commander": {
+      "version": "2.20.3",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+      "dev": true
+    },
+    "node_modules/commondir": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+      "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
+      "dev": true
+    },
+    "node_modules/compressible": {
+      "version": "2.0.18",
+      "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
+      "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
+      "dev": true,
+      "dependencies": {
+        "mime-db": ">= 1.43.0 < 2"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/compression": {
+      "version": "1.7.4",
+      "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz",
+      "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==",
+      "dev": true,
+      "dependencies": {
+        "accepts": "~1.3.5",
+        "bytes": "3.0.0",
+        "compressible": "~2.0.16",
+        "debug": "2.6.9",
+        "on-headers": "~1.0.2",
+        "safe-buffer": "5.1.2",
+        "vary": "~1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/compression/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/compression/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+    },
+    "node_modules/connect-history-api-fallback": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz",
+      "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/console-control-strings": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+      "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
+      "dev": true
+    },
+    "node_modules/content-disposition": {
+      "version": "0.5.4",
+      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+      "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "5.2.1"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/content-disposition/node_modules/safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/content-type": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+      "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/convert-source-map": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz",
+      "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==",
+      "dependencies": {
+        "safe-buffer": "~5.1.1"
+      }
+    },
+    "node_modules/cookie": {
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+      "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/cookie-signature": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+      "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
+      "dev": true
+    },
+    "node_modules/copy-anything": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz",
+      "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==",
+      "dev": true,
+      "dependencies": {
+        "is-what": "^3.14.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/mesqueeb"
+      }
+    },
+    "node_modules/copy-webpack-plugin": {
+      "version": "11.0.0",
+      "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz",
+      "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==",
+      "dev": true,
+      "dependencies": {
+        "fast-glob": "^3.2.11",
+        "glob-parent": "^6.0.1",
+        "globby": "^13.1.1",
+        "normalize-path": "^3.0.0",
+        "schema-utils": "^4.0.0",
+        "serialize-javascript": "^6.0.0"
+      },
+      "engines": {
+        "node": ">= 14.15.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      },
+      "peerDependencies": {
+        "webpack": "^5.1.0"
+      }
+    },
+    "node_modules/copy-webpack-plugin/node_modules/glob-parent": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+      "dev": true,
+      "dependencies": {
+        "is-glob": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/core-js": {
+      "version": "3.8.3",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.3.tgz",
+      "integrity": "sha512-KPYXeVZYemC2TkNEkX/01I+7yd+nX3KddKwZ1Ww7SKWdI2wQprSgLmrTddT8nw92AjEklTsPBoSdQBhbI1bQ6Q==",
+      "hasInstallScript": true,
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/core-js"
+      }
+    },
+    "node_modules/core-js-compat": {
+      "version": "3.27.2",
+      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.27.2.tgz",
+      "integrity": "sha512-welaYuF7ZtbYKGrIy7y3eb40d37rG1FvzEOfe7hSLd2iD6duMDqUhRfSvCGyC46HhR6Y8JXXdZ2lnRUMkPBpvg==",
+      "dev": true,
+      "dependencies": {
+        "browserslist": "^4.21.4"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/core-js"
+      }
+    },
+    "node_modules/core-util-is": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
+      "dev": true
+    },
+    "node_modules/cosmiconfig": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
+      "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
+      "dev": true,
+      "dependencies": {
+        "@types/parse-json": "^4.0.0",
+        "import-fresh": "^3.2.1",
+        "parse-json": "^5.0.0",
+        "path-type": "^4.0.0",
+        "yaml": "^1.10.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/critters": {
+      "version": "0.0.16",
+      "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz",
+      "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==",
+      "dev": true,
+      "dependencies": {
+        "chalk": "^4.1.0",
+        "css-select": "^4.2.0",
+        "parse5": "^6.0.1",
+        "parse5-htmlparser2-tree-adapter": "^6.0.1",
+        "postcss": "^8.3.7",
+        "pretty-bytes": "^5.3.0"
+      }
+    },
+    "node_modules/critters/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/critters/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/critters/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/critters/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/critters/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/critters/node_modules/parse5": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
+      "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
+      "dev": true
+    },
+    "node_modules/critters/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/cross-spawn": {
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
+      "dev": true,
+      "dependencies": {
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/css-loader": {
+      "version": "6.7.3",
+      "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz",
+      "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==",
+      "dev": true,
+      "dependencies": {
+        "icss-utils": "^5.1.0",
+        "postcss": "^8.4.19",
+        "postcss-modules-extract-imports": "^3.0.0",
+        "postcss-modules-local-by-default": "^4.0.0",
+        "postcss-modules-scope": "^3.0.0",
+        "postcss-modules-values": "^4.0.0",
+        "postcss-value-parser": "^4.2.0",
+        "semver": "^7.3.8"
+      },
+      "engines": {
+        "node": ">= 12.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      },
+      "peerDependencies": {
+        "webpack": "^5.0.0"
+      }
+    },
+    "node_modules/css-loader/node_modules/semver": {
+      "version": "7.3.8",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/css-select": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
+      "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
+      "dev": true,
+      "dependencies": {
+        "boolbase": "^1.0.0",
+        "css-what": "^6.0.1",
+        "domhandler": "^4.3.1",
+        "domutils": "^2.8.0",
+        "nth-check": "^2.0.1"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/css-selector-tokenizer": {
+      "version": "0.7.3",
+      "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz",
+      "integrity": "sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg==",
+      "dev": true,
+      "dependencies": {
+        "cssesc": "^3.0.0",
+        "fastparse": "^1.1.2"
+      }
+    },
+    "node_modules/css-what": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+      "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/fb55"
+      }
+    },
+    "node_modules/cssauron": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz",
+      "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=",
+      "dev": true,
+      "dependencies": {
+        "through": "X.X.X"
+      }
+    },
+    "node_modules/cssesc": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+      "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+      "dev": true,
+      "bin": {
+        "cssesc": "bin/cssesc"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/damerau-levenshtein": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz",
+      "integrity": "sha512-JVrozIeElnj3QzfUIt8tB8YMluBJom4Vw9qTPpjGYQ9fYlB3D/rb6OordUxf3xeFB35LKWs0xqcO5U6ySvBtug==",
+      "dev": true
+    },
+    "node_modules/dashdash": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+      "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
+      "dev": true,
+      "dependencies": {
+        "assert-plus": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/date-fns": {
+      "version": "1.30.1",
+      "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz",
+      "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw=="
+    },
+    "node_modules/debug": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz",
+      "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==",
+      "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)",
+      "dependencies": {
+        "ms": "2.1.2"
+      },
+      "engines": {
+        "node": ">=6.0"
+      },
+      "peerDependenciesMeta": {
+        "supports-color": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/default-gateway": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz",
+      "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==",
+      "dev": true,
+      "dependencies": {
+        "execa": "^5.0.0"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/defaults": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
+      "integrity": "sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==",
+      "dev": true,
+      "dependencies": {
+        "clone": "^1.0.2"
+      }
+    },
+    "node_modules/define-lazy-prop": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
+      "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/delayed-stream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/delegates": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+      "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
+      "dev": true
+    },
+    "node_modules/depd": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+      "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/dependency-graph": {
+      "version": "0.7.2",
+      "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.7.2.tgz",
+      "integrity": "sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ==",
+      "engines": {
+        "node": ">= 0.6.0"
+      }
+    },
+    "node_modules/destroy": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
+      "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8",
+        "npm": "1.2.8000 || >= 1.4.16"
+      }
+    },
+    "node_modules/detect-node": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
+      "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
+      "dev": true
+    },
+    "node_modules/diff": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
+      "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.3.1"
+      }
+    },
+    "node_modules/dir-glob": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+      "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+      "dev": true,
+      "dependencies": {
+        "path-type": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/dns-equal": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
+      "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==",
+      "dev": true
+    },
+    "node_modules/dns-packet": {
+      "version": "5.4.0",
+      "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz",
+      "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==",
+      "dev": true,
+      "dependencies": {
+        "@leichtgewicht/ip-codec": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/dom-serializer": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
+      "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
+      "dev": true,
+      "dependencies": {
+        "domelementtype": "^2.0.1",
+        "domhandler": "^4.2.0",
+        "entities": "^2.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+      }
+    },
+    "node_modules/domelementtype": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+      "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fb55"
+        }
+      ]
+    },
+    "node_modules/domhandler": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
+      "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
+      "dev": true,
+      "dependencies": {
+        "domelementtype": "^2.2.0"
+      },
+      "engines": {
+        "node": ">= 4"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/domhandler?sponsor=1"
+      }
+    },
+    "node_modules/domino": {
+      "version": "2.1.6",
+      "resolved": "https://registry.npmjs.org/domino/-/domino-2.1.6.tgz",
+      "integrity": "sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ=="
+    },
+    "node_modules/domutils": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
+      "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
+      "dev": true,
+      "dependencies": {
+        "dom-serializer": "^1.0.1",
+        "domelementtype": "^2.2.0",
+        "domhandler": "^4.2.0"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/domutils?sponsor=1"
+      }
+    },
+    "node_modules/duplexer": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz",
+      "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
+      "dev": true
+    },
+    "node_modules/ecc-jsbn": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
+      "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
+      "dev": true,
+      "dependencies": {
+        "jsbn": "~0.1.0",
+        "safer-buffer": "^2.1.0"
+      }
+    },
+    "node_modules/ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+      "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
+      "dev": true
+    },
+    "node_modules/electron-to-chromium": {
+      "version": "1.4.292",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.292.tgz",
+      "integrity": "sha512-ESWOSyJy5odDlE8wvh5NNAMORv4r6assPwIPGHEMWrWD0SONXcG/xT+9aD9CQyeRwyYDPo6dJT4Bbeg5uevVQQ=="
+    },
+    "node_modules/emoji-regex": {
+      "version": "8.0.0",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+      "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+    },
+    "node_modules/emojis-list": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz",
+      "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+      "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/encoding": {
+      "version": "0.1.13",
+      "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
+      "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
+      "dev": true,
+      "optional": true,
+      "dependencies": {
+        "iconv-lite": "^0.6.2"
+      }
+    },
+    "node_modules/encoding/node_modules/iconv-lite": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+      "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+      "dev": true,
+      "optional": true,
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/enhanced-resolve": {
+      "version": "5.12.0",
+      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz",
+      "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==",
+      "dev": true,
+      "dependencies": {
+        "graceful-fs": "^4.2.4",
+        "tapable": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/entities": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+      "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/env-paths": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+      "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/err-code": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz",
+      "integrity": "sha512-CJAN+O0/yA1CKfRn9SXOGctSpEM7DCon/r/5r2eXFMY2zCCJBasFhcM5I+1kh3Ap11FsQCX+vGHceNPvpWKhoA==",
+      "dev": true
+    },
+    "node_modules/errno": {
+      "version": "0.1.8",
+      "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
+      "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
+      "dev": true,
+      "optional": true,
+      "dependencies": {
+        "prr": "~1.0.1"
+      },
+      "bin": {
+        "errno": "cli.js"
+      }
+    },
+    "node_modules/error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "dev": true,
+      "dependencies": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
+    "node_modules/es-module-lexer": {
+      "version": "0.9.3",
+      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz",
+      "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==",
+      "dev": true
+    },
+    "node_modules/esbuild": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.8.tgz",
+      "integrity": "sha512-g24ybC3fWhZddZK6R3uD2iF/RIPnRpwJAqLov6ouX3hMbY4+tKolP0VMF3zuIYCaXun+yHwS5IPQ91N2BT191g==",
+      "dev": true,
+      "hasInstallScript": true,
+      "optional": true,
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "optionalDependencies": {
+        "@esbuild/android-arm": "0.17.8",
+        "@esbuild/android-arm64": "0.17.8",
+        "@esbuild/android-x64": "0.17.8",
+        "@esbuild/darwin-arm64": "0.17.8",
+        "@esbuild/darwin-x64": "0.17.8",
+        "@esbuild/freebsd-arm64": "0.17.8",
+        "@esbuild/freebsd-x64": "0.17.8",
+        "@esbuild/linux-arm": "0.17.8",
+        "@esbuild/linux-arm64": "0.17.8",
+        "@esbuild/linux-ia32": "0.17.8",
+        "@esbuild/linux-loong64": "0.17.8",
+        "@esbuild/linux-mips64el": "0.17.8",
+        "@esbuild/linux-ppc64": "0.17.8",
+        "@esbuild/linux-riscv64": "0.17.8",
+        "@esbuild/linux-s390x": "0.17.8",
+        "@esbuild/linux-x64": "0.17.8",
+        "@esbuild/netbsd-x64": "0.17.8",
+        "@esbuild/openbsd-x64": "0.17.8",
+        "@esbuild/sunos-x64": "0.17.8",
+        "@esbuild/win32-arm64": "0.17.8",
+        "@esbuild/win32-ia32": "0.17.8",
+        "@esbuild/win32-x64": "0.17.8"
+      }
+    },
+    "node_modules/esbuild-wasm": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.17.8.tgz",
+      "integrity": "sha512-zCmpxv95E0FuCmvdw1K836UHnj4EdiQnFfjTby35y3LAjRPtXMj3sbHDRHjbD8Mqg5lTwq3knacr/1qIFU51CQ==",
+      "dev": true,
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+      "dev": true
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/eslint-scope": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+      "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
+      "dev": true,
+      "dependencies": {
+        "esrecurse": "^4.3.0",
+        "estraverse": "^4.1.1"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/esprima": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
+      "dev": true,
+      "bin": {
+        "esparse": "bin/esparse.js",
+        "esvalidate": "bin/esvalidate.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/esrecurse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
+      "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
+      "dev": true,
+      "dependencies": {
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/esrecurse/node_modules/estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/estraverse": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
+      "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/esutils": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
+      "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/etag": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+      "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/eventemitter-asyncresource": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz",
+      "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==",
+      "dev": true
+    },
+    "node_modules/eventemitter3": {
+      "version": "4.0.7",
+      "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz",
+      "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
+      "dev": true
+    },
+    "node_modules/events": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+      "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.x"
+      }
+    },
+    "node_modules/execa": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
+      "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
+      "dev": true,
+      "dependencies": {
+        "cross-spawn": "^7.0.3",
+        "get-stream": "^6.0.0",
+        "human-signals": "^2.1.0",
+        "is-stream": "^2.0.0",
+        "merge-stream": "^2.0.0",
+        "npm-run-path": "^4.0.1",
+        "onetime": "^5.1.2",
+        "signal-exit": "^3.0.3",
+        "strip-final-newline": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sindresorhus/execa?sponsor=1"
+      }
+    },
+    "node_modules/express": {
+      "version": "4.18.2",
+      "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
+      "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
+      "dev": true,
+      "dependencies": {
+        "accepts": "~1.3.8",
+        "array-flatten": "1.1.1",
+        "body-parser": "1.20.1",
+        "content-disposition": "0.5.4",
+        "content-type": "~1.0.4",
+        "cookie": "0.5.0",
+        "cookie-signature": "1.0.6",
+        "debug": "2.6.9",
+        "depd": "2.0.0",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "finalhandler": "1.2.0",
+        "fresh": "0.5.2",
+        "http-errors": "2.0.0",
+        "merge-descriptors": "1.0.1",
+        "methods": "~1.1.2",
+        "on-finished": "2.4.1",
+        "parseurl": "~1.3.3",
+        "path-to-regexp": "0.1.7",
+        "proxy-addr": "~2.0.7",
+        "qs": "6.11.0",
+        "range-parser": "~1.2.1",
+        "safe-buffer": "5.2.1",
+        "send": "0.18.0",
+        "serve-static": "1.15.0",
+        "setprototypeof": "1.2.0",
+        "statuses": "2.0.1",
+        "type-is": "~1.6.18",
+        "utils-merge": "1.0.1",
+        "vary": "~1.1.2"
+      },
+      "engines": {
+        "node": ">= 0.10.0"
+      }
+    },
+    "node_modules/express/node_modules/array-flatten": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+      "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
+      "dev": true
+    },
+    "node_modules/express/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/express/node_modules/depd": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/express/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true
+    },
+    "node_modules/express/node_modules/safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/extend": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+      "dev": true
+    },
+    "node_modules/external-editor": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
+      "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==",
+      "dev": true,
+      "dependencies": {
+        "chardet": "^0.7.0",
+        "iconv-lite": "^0.4.24",
+        "tmp": "^0.0.33"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/extsprintf": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
+      "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=",
+      "dev": true,
+      "engines": [
+        "node >=0.6.0"
+      ]
+    },
+    "node_modules/fast-deep-equal": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
+      "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
+      "dev": true
+    },
+    "node_modules/fast-glob": {
+      "version": "3.2.12",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
+      "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
+      "dev": true,
+      "dependencies": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.4"
+      },
+      "engines": {
+        "node": ">=8.6.0"
+      }
+    },
+    "node_modules/fast-json-stable-stringify": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
+      "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
+      "dev": true
+    },
+    "node_modules/fastparse": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
+      "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
+      "dev": true
+    },
+    "node_modules/fastq": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
+      "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
+      "dev": true,
+      "dependencies": {
+        "reusify": "^1.0.4"
+      }
+    },
+    "node_modules/faye-websocket": {
+      "version": "0.11.4",
+      "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
+      "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
+      "dev": true,
+      "dependencies": {
+        "websocket-driver": ">=0.5.1"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/figures": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
+      "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==",
+      "dev": true,
+      "dependencies": {
+        "escape-string-regexp": "^1.0.5"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/finalhandler": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+      "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
+      "dev": true,
+      "dependencies": {
+        "debug": "2.6.9",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "on-finished": "2.4.1",
+        "parseurl": "~1.3.3",
+        "statuses": "2.0.1",
+        "unpipe": "~1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/finalhandler/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/finalhandler/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true
+    },
+    "node_modules/find-cache-dir": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
+      "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
+      "dev": true,
+      "dependencies": {
+        "commondir": "^1.0.1",
+        "make-dir": "^3.0.2",
+        "pkg-dir": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/avajs/find-cache-dir?sponsor=1"
+      }
+    },
+    "node_modules/find-cache-dir/node_modules/make-dir": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
+      "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
+      "dev": true,
+      "dependencies": {
+        "semver": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/find-cache-dir/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/find-up": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
+      "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
+      "dependencies": {
+        "locate-path": "^5.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/follow-redirects": {
+      "version": "1.15.2",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
+      "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://github.com/sponsors/RubenVerborgh"
+        }
+      ],
+      "engines": {
+        "node": ">=4.0"
+      },
+      "peerDependenciesMeta": {
+        "debug": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/forever-agent": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
+      "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
+      "dev": true,
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/form-data": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
+      "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
+      "dev": true,
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.6",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 0.12"
+      }
+    },
+    "node_modules/forwarded": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+      "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/fraction.js": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
+      "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==",
+      "dev": true,
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "type": "patreon",
+        "url": "https://www.patreon.com/infusion"
+      }
+    },
+    "node_modules/fresh": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+      "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/fs-extra": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz",
+      "integrity": "sha512-wYid1zXctNLgas1pZ8q8ChdsnGg4DHZVqMzJ7pOE85q5BppAEXgQGSoOjVgrcw5yI7pzz49p9AfMhM7z5PRuaw==",
+      "dependencies": {
+        "graceful-fs": "^4.1.2",
+        "jsonfile": "^4.0.0",
+        "universalify": "^0.1.0"
+      }
+    },
+    "node_modules/fs-minipass": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
+      "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
+      "dev": true,
+      "dependencies": {
+        "minipass": "^3.0.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/fs-monkey": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz",
+      "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==",
+      "dev": true
+    },
+    "node_modules/fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+    },
+    "node_modules/gauge": {
+      "version": "2.7.4",
+      "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+      "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==",
+      "dev": true,
+      "dependencies": {
+        "aproba": "^1.0.3",
+        "console-control-strings": "^1.0.0",
+        "has-unicode": "^2.0.0",
+        "object-assign": "^4.1.0",
+        "signal-exit": "^3.0.0",
+        "string-width": "^1.0.1",
+        "strip-ansi": "^3.0.1",
+        "wide-align": "^1.1.0"
+      }
+    },
+    "node_modules/gauge/node_modules/ansi-regex": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+      "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/gauge/node_modules/is-fullwidth-code-point": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+      "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==",
+      "dev": true,
+      "dependencies": {
+        "number-is-nan": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/gauge/node_modules/string-width": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+      "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+      "dev": true,
+      "dependencies": {
+        "code-point-at": "^1.0.0",
+        "is-fullwidth-code-point": "^1.0.0",
+        "strip-ansi": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/gauge/node_modules/strip-ansi": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+      "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+      "dev": true,
+      "dependencies": {
+        "ansi-regex": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/gensync": {
+      "version": "1.0.0-beta.2",
+      "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
+      "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/get-caller-file": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+      "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+      "engines": {
+        "node": "6.* || 8.* || >= 10.*"
+      }
+    },
+    "node_modules/get-intrinsic": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
+      "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
+      "dev": true,
+      "dependencies": {
+        "function-bind": "^1.1.1",
+        "has": "^1.0.3",
+        "has-symbols": "^1.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/get-package-type": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
+      "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/get-stream": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+      "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/getpass": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
+      "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
+      "dev": true,
+      "dependencies": {
+        "assert-plus": "^1.0.0"
+      }
+    },
+    "node_modules/glob": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+      "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/glob-to-regexp": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
+      "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
+      "dev": true
+    },
+    "node_modules/globals": {
+      "version": "11.12.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
+      "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/globby": {
+      "version": "13.1.3",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz",
+      "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==",
+      "dev": true,
+      "dependencies": {
+        "dir-glob": "^3.0.1",
+        "fast-glob": "^3.2.11",
+        "ignore": "^5.2.0",
+        "merge2": "^1.4.1",
+        "slash": "^4.0.0"
+      },
+      "engines": {
+        "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/graceful-fs": {
+      "version": "4.2.10",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
+    },
+    "node_modules/guacamole-common-js": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/guacamole-common-js/-/guacamole-common-js-1.2.0.tgz",
+      "integrity": "sha512-QshVHQq3t4KAdf6PpOEBZNLwl+uMA9e8jNfTrudxpmxZPPJ+1b7QiYbVV1t9cZrmvDLy4I/tga+xHkWgNaEerw=="
+    },
+    "node_modules/gzip-size": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz",
+      "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==",
+      "dev": true,
+      "dependencies": {
+        "duplexer": "^0.1.2"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/handle-thing": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz",
+      "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==",
+      "dev": true
+    },
+    "node_modules/har-schema": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+      "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/har-validator": {
+      "version": "5.1.5",
+      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz",
+      "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
+      "deprecated": "this library is no longer supported",
+      "dev": true,
+      "dependencies": {
+        "ajv": "^6.12.3",
+        "har-schema": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "dependencies": {
+        "function-bind": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/has-symbols": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/has-unicode": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+      "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==",
+      "dev": true
+    },
+    "node_modules/hdr-histogram-js": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz",
+      "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==",
+      "dev": true,
+      "dependencies": {
+        "@assemblyscript/loader": "^0.10.1",
+        "base64-js": "^1.2.0",
+        "pako": "^1.0.3"
+      }
+    },
+    "node_modules/hdr-histogram-percentiles-obj": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz",
+      "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==",
+      "dev": true
+    },
+    "node_modules/hosted-git-info": {
+      "version": "3.0.8",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz",
+      "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/hpack.js": {
+      "version": "2.1.6",
+      "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
+      "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.1",
+        "obuf": "^1.0.0",
+        "readable-stream": "^2.0.1",
+        "wbuf": "^1.1.0"
+      }
+    },
+    "node_modules/html-entities": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz",
+      "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==",
+      "dev": true
+    },
+    "node_modules/http-cache-semantics": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
+      "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
+      "dev": true
+    },
+    "node_modules/http-deceiver": {
+      "version": "1.2.7",
+      "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
+      "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==",
+      "dev": true
+    },
+    "node_modules/http-errors": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+      "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
+      "dev": true,
+      "dependencies": {
+        "depd": "2.0.0",
+        "inherits": "2.0.4",
+        "setprototypeof": "1.2.0",
+        "statuses": "2.0.1",
+        "toidentifier": "1.0.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/http-errors/node_modules/depd": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/http-parser-js": {
+      "version": "0.5.8",
+      "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz",
+      "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==",
+      "dev": true
+    },
+    "node_modules/http-proxy": {
+      "version": "1.18.1",
+      "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
+      "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
+      "dev": true,
+      "dependencies": {
+        "eventemitter3": "^4.0.0",
+        "follow-redirects": "^1.0.0",
+        "requires-port": "^1.0.0"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/http-proxy-agent": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
+      "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
+      "dev": true,
+      "dependencies": {
+        "@tootallnate/once": "1",
+        "agent-base": "6",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/http-proxy-middleware": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz",
+      "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==",
+      "dev": true,
+      "dependencies": {
+        "@types/http-proxy": "^1.17.8",
+        "http-proxy": "^1.18.1",
+        "is-glob": "^4.0.1",
+        "is-plain-obj": "^3.0.0",
+        "micromatch": "^4.0.2"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      },
+      "peerDependencies": {
+        "@types/express": "^4.17.13"
+      },
+      "peerDependenciesMeta": {
+        "@types/express": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/http-signature": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+      "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
+      "dev": true,
+      "dependencies": {
+        "assert-plus": "^1.0.0",
+        "jsprim": "^1.2.2",
+        "sshpk": "^1.7.0"
+      },
+      "engines": {
+        "node": ">=0.8",
+        "npm": ">=1.3.7"
+      }
+    },
+    "node_modules/https-proxy-agent": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+      "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
+      "dev": true,
+      "dependencies": {
+        "agent-base": "6",
+        "debug": "4"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/human-signals": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
+      "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10.17.0"
+      }
+    },
+    "node_modules/humanize-ms": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
+      "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
+      "dev": true,
+      "dependencies": {
+        "ms": "^2.0.0"
+      }
+    },
+    "node_modules/iconv-lite": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+      "dev": true,
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/icss-utils": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
+      "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
+      "dev": true,
+      "engines": {
+        "node": "^10 || ^12 || >= 14"
+      },
+      "peerDependencies": {
+        "postcss": "^8.1.0"
+      }
+    },
+    "node_modules/ieee754": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/ignore": {
+      "version": "5.2.4",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+      "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/ignore-walk": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz",
+      "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==",
+      "dev": true,
+      "dependencies": {
+        "minimatch": "^3.0.4"
+      }
+    },
+    "node_modules/image-size": {
+      "version": "0.5.5",
+      "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz",
+      "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==",
+      "dev": true,
+      "optional": true,
+      "bin": {
+        "image-size": "bin/image-size.js"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/immutable": {
+      "version": "4.2.4",
+      "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.4.tgz",
+      "integrity": "sha512-WDxL3Hheb1JkRN3sQkyujNlL/xRjAo3rJtaU5xeufUauG66JdMr32bLj4gF+vWl84DIA3Zxw7tiAjneYzRRw+w==",
+      "dev": true
+    },
+    "node_modules/import-fresh": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+      "dev": true,
+      "dependencies": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/import-fresh/node_modules/resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/imurmurhash": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
+      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.19"
+      }
+    },
+    "node_modules/indent-string": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
+      "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/infer-owner": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
+      "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==",
+      "dev": true
+    },
+    "node_modules/inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "dependencies": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
+    "node_modules/ini": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz",
+      "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/inquirer": {
+      "version": "7.3.3",
+      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz",
+      "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-escapes": "^4.2.1",
+        "chalk": "^4.1.0",
+        "cli-cursor": "^3.1.0",
+        "cli-width": "^3.0.0",
+        "external-editor": "^3.0.3",
+        "figures": "^3.0.0",
+        "lodash": "^4.17.19",
+        "mute-stream": "0.0.8",
+        "run-async": "^2.4.0",
+        "rxjs": "^6.6.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0",
+        "through": "^2.3.6"
+      },
+      "engines": {
+        "node": ">=8.0.0"
+      }
+    },
+    "node_modules/inquirer/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/inquirer/node_modules/chalk": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
+      "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/inquirer/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/inquirer/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/inquirer/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/inquirer/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ip": {
+      "version": "1.1.8",
+      "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
+      "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==",
+      "dev": true
+    },
+    "node_modules/ipaddr.js": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz",
+      "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==",
+      "dev": true,
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
+      "dev": true
+    },
+    "node_modules/is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "dependencies": {
+        "binary-extensions": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-core-module": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz",
+      "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==",
+      "dependencies": {
+        "has": "^1.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-docker": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
+      "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
+      "dev": true,
+      "bin": {
+        "is-docker": "cli.js"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-fullwidth-code-point": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+      "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-interactive": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
+      "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-lambda": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz",
+      "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==",
+      "dev": true
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/is-plain-obj": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz",
+      "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-plain-object": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+      "dev": true,
+      "dependencies": {
+        "isobject": "^3.0.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-stream": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-typedarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
+      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
+      "dev": true
+    },
+    "node_modules/is-unicode-supported": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+      "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/is-what": {
+      "version": "3.14.1",
+      "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz",
+      "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==",
+      "dev": true
+    },
+    "node_modules/is-wsl": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
+      "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
+      "dev": true,
+      "dependencies": {
+        "is-docker": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/isarray": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
+      "dev": true
+    },
+    "node_modules/isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+      "dev": true
+    },
+    "node_modules/isobject": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+      "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/isstream": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
+      "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+      "dev": true
+    },
+    "node_modules/istanbul-lib-coverage": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
+      "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-instrument": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
+      "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/core": "^7.12.3",
+        "@babel/parser": "^7.14.7",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-coverage": "^3.2.0",
+        "semver": "^6.3.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/istanbul-lib-instrument/node_modules/semver": {
+      "version": "6.3.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+      "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      }
+    },
+    "node_modules/jest-worker": {
+      "version": "27.5.1",
+      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
+      "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
+      "dev": true,
+      "dependencies": {
+        "@types/node": "*",
+        "merge-stream": "^2.0.0",
+        "supports-color": "^8.0.0"
+      },
+      "engines": {
+        "node": ">= 10.13.0"
+      }
+    },
+    "node_modules/jest-worker/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/jest-worker/node_modules/supports-color": {
+      "version": "8.1.1",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+      "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/supports-color?sponsor=1"
+      }
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+    },
+    "node_modules/js-yaml": {
+      "version": "3.14.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
+      "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
+      "dev": true,
+      "dependencies": {
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
+    "node_modules/jsbn": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
+      "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
+      "dev": true
+    },
+    "node_modules/jsesc": {
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
+      "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==",
+      "bin": {
+        "jsesc": "bin/jsesc"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/json-parse-even-better-errors": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
+      "dev": true
+    },
+    "node_modules/json-schema": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
+      "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
+      "dev": true
+    },
+    "node_modules/json-schema-traverse": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
+      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
+      "dev": true
+    },
+    "node_modules/json-stringify-safe": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+      "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
+      "dev": true
+    },
+    "node_modules/json5": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+      "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
+      "bin": {
+        "json5": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/jsonc-parser": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz",
+      "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==",
+      "dev": true
+    },
+    "node_modules/jsonfile": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+      "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
+      "optionalDependencies": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "node_modules/jsonparse": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+      "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==",
+      "dev": true,
+      "engines": [
+        "node >= 0.2.0"
+      ]
+    },
+    "node_modules/jsprim": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
+      "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
+      "dev": true,
+      "dependencies": {
+        "assert-plus": "1.0.0",
+        "extsprintf": "1.3.0",
+        "json-schema": "0.4.0",
+        "verror": "1.10.0"
+      },
+      "engines": {
+        "node": ">=0.6.0"
+      }
+    },
+    "node_modules/karma-source-map-support": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz",
+      "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==",
+      "dev": true,
+      "dependencies": {
+        "source-map-support": "^0.5.5"
+      }
+    },
+    "node_modules/kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/klona": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz",
+      "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/less": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz",
+      "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==",
+      "dev": true,
+      "dependencies": {
+        "copy-anything": "^2.0.1",
+        "parse-node-version": "^1.0.1",
+        "tslib": "^2.3.0"
+      },
+      "bin": {
+        "lessc": "bin/lessc"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "optionalDependencies": {
+        "errno": "^0.1.1",
+        "graceful-fs": "^4.1.2",
+        "image-size": "~0.5.0",
+        "make-dir": "^2.1.0",
+        "mime": "^1.4.1",
+        "needle": "^3.1.0",
+        "source-map": "~0.6.0"
+      }
+    },
+    "node_modules/less-loader": {
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.0.tgz",
+      "integrity": "sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==",
+      "dev": true,
+      "dependencies": {
+        "klona": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 14.15.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      },
+      "peerDependencies": {
+        "less": "^3.5.0 || ^4.0.0",
+        "webpack": "^5.0.0"
+      }
+    },
+    "node_modules/less/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "optional": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/license-webpack-plugin": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz",
+      "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==",
+      "dev": true,
+      "dependencies": {
+        "webpack-sources": "^3.0.0"
+      },
+      "peerDependenciesMeta": {
+        "webpack": {
+          "optional": true
+        },
+        "webpack-sources": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/lines-and-columns": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+      "dev": true
+    },
+    "node_modules/loader-runner": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
+      "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6.11.5"
+      }
+    },
+    "node_modules/loader-utils": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz",
+      "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 12.13.0"
+      }
+    },
+    "node_modules/locate-path": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
+      "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^4.1.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+    },
+    "node_modules/lodash.debounce": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+      "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
+      "dev": true
+    },
+    "node_modules/lodash.isequal": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+      "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
+    },
+    "node_modules/log-symbols": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+      "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
+      "dev": true,
+      "dependencies": {
+        "chalk": "^4.1.0",
+        "is-unicode-supported": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/log-symbols/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/log-symbols/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/log-symbols/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/log-symbols/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/log-symbols/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/log-symbols/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/lru-cache": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
+      "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
+      "dev": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/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==",
+      "dependencies": {
+        "sourcemap-codec": "^1.4.4"
+      }
+    },
+    "node_modules/make-dir": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
+      "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
+      "dev": true,
+      "optional": true,
+      "dependencies": {
+        "pify": "^4.0.1",
+        "semver": "^5.6.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/make-error": {
+      "version": "1.3.6",
+      "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+      "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+      "dev": true
+    },
+    "node_modules/make-fetch-happen": {
+      "version": "8.0.14",
+      "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz",
+      "integrity": "sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ==",
+      "dev": true,
+      "dependencies": {
+        "agentkeepalive": "^4.1.3",
+        "cacache": "^15.0.5",
+        "http-cache-semantics": "^4.1.0",
+        "http-proxy-agent": "^4.0.1",
+        "https-proxy-agent": "^5.0.0",
+        "is-lambda": "^1.0.1",
+        "lru-cache": "^6.0.0",
+        "minipass": "^3.1.3",
+        "minipass-collect": "^1.0.2",
+        "minipass-fetch": "^1.3.2",
+        "minipass-flush": "^1.0.5",
+        "minipass-pipeline": "^1.2.4",
+        "promise-retry": "^2.0.1",
+        "socks-proxy-agent": "^5.0.0",
+        "ssri": "^8.0.0"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/make-fetch-happen/node_modules/err-code": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz",
+      "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==",
+      "dev": true
+    },
+    "node_modules/make-fetch-happen/node_modules/promise-retry": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz",
+      "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==",
+      "dev": true,
+      "dependencies": {
+        "err-code": "^2.0.2",
+        "retry": "^0.12.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/make-fetch-happen/node_modules/retry": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
+      "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=",
+      "dev": true,
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/media-typer": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+      "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/memfs": {
+      "version": "3.4.13",
+      "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.13.tgz",
+      "integrity": "sha512-omTM41g3Skpvx5dSYeZIbXKcXoAVc/AoMNwn9TKx++L/gaen/+4TTttmu8ZSch5vfVJ8uJvGbroTsIlslRg6lg==",
+      "dev": true,
+      "dependencies": {
+        "fs-monkey": "^1.0.3"
+      },
+      "engines": {
+        "node": ">= 4.0.0"
+      }
+    },
+    "node_modules/merge-descriptors": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+      "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
+      "dev": true
+    },
+    "node_modules/merge-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+      "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+      "dev": true
+    },
+    "node_modules/merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/methods": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+      "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/micromatch": {
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+      "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+      "dev": true,
+      "dependencies": {
+        "braces": "^3.0.2",
+        "picomatch": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
+    "node_modules/mime": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
+      "dev": true,
+      "bin": {
+        "mime": "cli.js"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/mime-db": {
+      "version": "1.52.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mime-types": {
+      "version": "2.1.35",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
+      "dev": true,
+      "dependencies": {
+        "mime-db": "1.52.0"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/mimic-fn": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
+      "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/mini-css-extract-plugin": {
+      "version": "2.7.2",
+      "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.2.tgz",
+      "integrity": "sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw==",
+      "dev": true,
+      "dependencies": {
+        "schema-utils": "^4.0.0"
+      },
+      "engines": {
+        "node": ">= 12.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      },
+      "peerDependencies": {
+        "webpack": "^5.0.0"
+      }
+    },
+    "node_modules/minimalistic-assert": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
+      "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
+      "dev": true
+    },
+    "node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/minimist": {
+      "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",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz",
+      "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==",
+      "dev": true,
+      "dependencies": {
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/minipass-collect": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz",
+      "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==",
+      "dev": true,
+      "dependencies": {
+        "minipass": "^3.0.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/minipass-fetch": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz",
+      "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==",
+      "dev": true,
+      "dependencies": {
+        "minipass": "^3.1.0",
+        "minipass-sized": "^1.0.3",
+        "minizlib": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "optionalDependencies": {
+        "encoding": "^0.1.12"
+      }
+    },
+    "node_modules/minipass-flush": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz",
+      "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==",
+      "dev": true,
+      "dependencies": {
+        "minipass": "^3.0.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/minipass-json-stream": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz",
+      "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==",
+      "dev": true,
+      "dependencies": {
+        "jsonparse": "^1.3.1",
+        "minipass": "^3.0.0"
+      }
+    },
+    "node_modules/minipass-pipeline": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz",
+      "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==",
+      "dev": true,
+      "dependencies": {
+        "minipass": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/minipass-sized": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz",
+      "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==",
+      "dev": true,
+      "dependencies": {
+        "minipass": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/minizlib": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
+      "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
+      "dev": true,
+      "dependencies": {
+        "minipass": "^3.0.0",
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/mkdirp": {
+      "version": "0.5.5",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
+      "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
+      "dev": true,
+      "dependencies": {
+        "minimist": "^1.2.5"
+      },
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      }
+    },
+    "node_modules/moment": {
+      "version": "2.29.4",
+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
+      "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/moment-timezone": {
+      "version": "0.5.35",
+      "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.35.tgz",
+      "integrity": "sha512-cY/pBOEXepQvlgli06ttCTKcIf8cD1nmNwOKQQAdHBqYApQSpAqotBMX0RJZNgMp6i0PlZuf1mFtnlyEkwyvFw==",
+      "dependencies": {
+        "moment": ">= 2.9.0"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/mrmime": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz",
+      "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/ms": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+    },
+    "node_modules/multicast-dns": {
+      "version": "7.2.5",
+      "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz",
+      "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==",
+      "dev": true,
+      "dependencies": {
+        "dns-packet": "^5.2.2",
+        "thunky": "^1.0.2"
+      },
+      "bin": {
+        "multicast-dns": "cli.js"
+      }
+    },
+    "node_modules/mute-stream": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
+      "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
+      "dev": true
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.4",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
+      "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
+      "dev": true,
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/needle": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz",
+      "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==",
+      "dev": true,
+      "optional": true,
+      "dependencies": {
+        "debug": "^3.2.6",
+        "iconv-lite": "^0.6.3",
+        "sax": "^1.2.4"
+      },
+      "bin": {
+        "needle": "bin/needle"
+      },
+      "engines": {
+        "node": ">= 4.4.x"
+      }
+    },
+    "node_modules/needle/node_modules/debug": {
+      "version": "3.2.7",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+      "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+      "dev": true,
+      "optional": true,
+      "dependencies": {
+        "ms": "^2.1.1"
+      }
+    },
+    "node_modules/needle/node_modules/iconv-lite": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+      "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+      "dev": true,
+      "optional": true,
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/negotiator": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+      "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/neo-async": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
+      "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
+      "dev": true
+    },
+    "node_modules/ng-daterangepicker": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/ng-daterangepicker/-/ng-daterangepicker-1.1.0.tgz",
+      "integrity": "sha512-xYY+ieQUlKADvvZ+Nqpm+Mi8+fSNzAvCvbOY+jVRRDemVFGOO6gDAP1SXsCvZZ3JSUpjKfuLEOSjS3C+C5w7zQ==",
+      "dependencies": {
+        "date-fns": "^1.29.0"
+      }
+    },
+    "node_modules/ng2-ace-editor": {
+      "version": "0.3.9",
+      "resolved": "https://registry.npmjs.org/ng2-ace-editor/-/ng2-ace-editor-0.3.9.tgz",
+      "integrity": "sha512-e8Q4YCirlL/OEiekewmzupG+zV3prYsiYmQnRzQzd0wNgsPjOLOdb0it7cCbzFfIXKGyIIHKTW5584WxPr2LnQ==",
+      "dependencies": {
+        "ace-builds": "^1.4.2",
+        "brace": "^0.11.1"
+      },
+      "peerDependencies": {
+        "@angular/core": "^7.0.0"
+      }
+    },
+    "node_modules/ngx-toastr": {
+      "version": "12.1.0",
+      "resolved": "https://registry.npmjs.org/ngx-toastr/-/ngx-toastr-12.1.0.tgz",
+      "integrity": "sha512-rytCRBhvuudj614Kfj9GoIVQDrFuLvHSMP1YrMwTmR1SNkNJZOpGKmaSDCCBrNDkSrGouzMWBlFbl1UDBBsiqw==",
+      "dependencies": {
+        "tslib": "^1.10.0"
+      },
+      "peerDependencies": {
+        "@angular/common": ">=9.0.0-0",
+        "@angular/core": ">=9.0.0-0",
+        "@angular/platform-browser": ">=9.0.0-0"
+      }
+    },
+    "node_modules/ngx-toastr/node_modules/tslib": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+    },
+    "node_modules/nice-napi": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz",
+      "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==",
+      "dev": true,
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "!win32"
+      ],
+      "dependencies": {
+        "node-addon-api": "^3.0.0",
+        "node-gyp-build": "^4.2.2"
+      }
+    },
+    "node_modules/node-addon-api": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
+      "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==",
+      "dev": true,
+      "optional": true
+    },
+    "node_modules/node-forge": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
+      "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 6.13.0"
+      }
+    },
+    "node_modules/node-gyp": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz",
+      "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==",
+      "dev": true,
+      "dependencies": {
+        "env-paths": "^2.2.0",
+        "glob": "^7.1.4",
+        "graceful-fs": "^4.2.3",
+        "nopt": "^5.0.0",
+        "npmlog": "^4.1.2",
+        "request": "^2.88.2",
+        "rimraf": "^3.0.2",
+        "semver": "^7.3.2",
+        "tar": "^6.0.2",
+        "which": "^2.0.2"
+      },
+      "bin": {
+        "node-gyp": "bin/node-gyp.js"
+      },
+      "engines": {
+        "node": ">= 10.12.0"
+      }
+    },
+    "node_modules/node-gyp-build": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz",
+      "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==",
+      "dev": true,
+      "optional": true,
+      "bin": {
+        "node-gyp-build": "bin.js",
+        "node-gyp-build-optional": "optional.js",
+        "node-gyp-build-test": "build-test.js"
+      }
+    },
+    "node_modules/node-gyp/node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "dev": true,
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/node-gyp/node_modules/semver": {
+      "version": "7.3.7",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+      "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.10",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz",
+      "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w=="
+    },
+    "node_modules/nopt": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
+      "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
+      "dev": true,
+      "dependencies": {
+        "abbrev": "1"
+      },
+      "bin": {
+        "nopt": "bin/nopt.js"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/normalize-range": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+      "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/npm-bundled": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz",
+      "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==",
+      "dev": true,
+      "dependencies": {
+        "npm-normalize-package-bin": "^1.0.1"
+      }
+    },
+    "node_modules/npm-install-checks": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-4.0.0.tgz",
+      "integrity": "sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w==",
+      "dev": true,
+      "dependencies": {
+        "semver": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/npm-install-checks/node_modules/semver": {
+      "version": "7.3.2",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
+      "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/npm-normalize-package-bin": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz",
+      "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==",
+      "dev": true
+    },
+    "node_modules/npm-package-arg": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.0.tgz",
+      "integrity": "sha512-/ep6QDxBkm9HvOhOg0heitSd7JHA1U7y1qhhlRlteYYAi9Pdb/ZV7FW5aHpkrpM8+P+4p/jjR8zCyKPBMBjSig==",
+      "dev": true,
+      "dependencies": {
+        "hosted-git-info": "^3.0.6",
+        "semver": "^7.0.0",
+        "validate-npm-package-name": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/npm-package-arg/node_modules/semver": {
+      "version": "7.3.2",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
+      "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/npm-packlist": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-2.2.2.tgz",
+      "integrity": "sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg==",
+      "dev": true,
+      "dependencies": {
+        "glob": "^7.1.6",
+        "ignore-walk": "^3.0.3",
+        "npm-bundled": "^1.1.1",
+        "npm-normalize-package-bin": "^1.0.1"
+      },
+      "bin": {
+        "npm-packlist": "bin/index.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/npm-packlist/node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "dev": true,
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/npm-pick-manifest": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.0.tgz",
+      "integrity": "sha512-ygs4k6f54ZxJXrzT0x34NybRlLeZ4+6nECAIbr2i0foTnijtS1TJiyzpqtuUAJOps/hO0tNDr8fRV5g+BtRlTw==",
+      "dev": true,
+      "dependencies": {
+        "npm-install-checks": "^4.0.0",
+        "npm-package-arg": "^8.0.0",
+        "semver": "^7.0.0"
+      }
+    },
+    "node_modules/npm-pick-manifest/node_modules/semver": {
+      "version": "7.3.2",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
+      "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
+      "dev": true,
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/npm-registry-fetch": {
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-9.0.0.tgz",
+      "integrity": "sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA==",
+      "dev": true,
+      "dependencies": {
+        "@npmcli/ci-detect": "^1.0.0",
+        "lru-cache": "^6.0.0",
+        "make-fetch-happen": "^8.0.9",
+        "minipass": "^3.1.3",
+        "minipass-fetch": "^1.3.0",
+        "minipass-json-stream": "^1.0.1",
+        "minizlib": "^2.0.0",
+        "npm-package-arg": "^8.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/npm-run-path": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+      "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
+      "dev": true,
+      "dependencies": {
+        "path-key": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/npmlog": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+      "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+      "dev": true,
+      "dependencies": {
+        "are-we-there-yet": "~1.1.2",
+        "console-control-strings": "~1.1.0",
+        "gauge": "~2.7.3",
+        "set-blocking": "~2.0.0"
+      }
+    },
+    "node_modules/nth-check": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+      "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
+      "dev": true,
+      "dependencies": {
+        "boolbase": "^1.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/nth-check?sponsor=1"
+      }
+    },
+    "node_modules/number-is-nan": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+      "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/oauth-sign": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
+      "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
+      "dev": true,
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-inspect": {
+      "version": "1.12.3",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
+      "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
+      "dev": true,
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/obuf": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
+      "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==",
+      "dev": true
+    },
+    "node_modules/on-finished": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
+      "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
+      "dev": true,
+      "dependencies": {
+        "ee-first": "1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/on-headers": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
+      "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/onetime": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
+      "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
+      "dev": true,
+      "dependencies": {
+        "mimic-fn": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/open": {
+      "version": "7.4.0",
+      "resolved": "https://registry.npmjs.org/open/-/open-7.4.0.tgz",
+      "integrity": "sha512-PGoBCX/lclIWlpS/R2PQuIR4NJoXh6X5AwVzE7WXnWRGvHg7+4TBCgsujUgiPpm0K1y4qvQeWnCWVTpTKZBtvA==",
+      "dev": true,
+      "dependencies": {
+        "is-docker": "^2.0.0",
+        "is-wsl": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/opener": {
+      "version": "1.5.2",
+      "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz",
+      "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
+      "dev": true,
+      "bin": {
+        "opener": "bin/opener-bin.js"
+      }
+    },
+    "node_modules/ora": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz",
+      "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==",
+      "dev": true,
+      "dependencies": {
+        "bl": "^4.0.3",
+        "chalk": "^4.1.0",
+        "cli-cursor": "^3.1.0",
+        "cli-spinners": "^2.5.0",
+        "is-interactive": "^1.0.0",
+        "log-symbols": "^4.0.0",
+        "strip-ansi": "^6.0.0",
+        "wcwidth": "^1.0.1"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/ora/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/ora/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/ora/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/ora/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/ora/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/ora/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/os-tmpdir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/p-limit": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
+      "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
+      "dependencies": {
+        "p-try": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-locate": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
+      "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/p-map": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
+      "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
+      "dev": true,
+      "dependencies": {
+        "aggregate-error": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/p-retry": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz",
+      "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/retry": "0.12.0",
+        "retry": "^0.13.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/p-retry/node_modules/retry": {
+      "version": "0.13.1",
+      "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
+      "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/p-try": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/pacote": {
+      "version": "11.2.4",
+      "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.2.4.tgz",
+      "integrity": "sha512-GfTeVQGJ6WyBQbQD4t3ocHbyOmTQLmWjkCKSZPmKiGFKYKNUaM5U2gbLzUW8WG1XmS9yQFnsTFA0k3o1+q4klQ==",
+      "dev": true,
+      "dependencies": {
+        "@npmcli/git": "^2.0.1",
+        "@npmcli/installed-package-contents": "^1.0.5",
+        "@npmcli/promise-spawn": "^1.2.0",
+        "@npmcli/run-script": "^1.3.0",
+        "cacache": "^15.0.5",
+        "chownr": "^2.0.0",
+        "fs-minipass": "^2.1.0",
+        "infer-owner": "^1.0.4",
+        "minipass": "^3.1.3",
+        "mkdirp": "^1.0.3",
+        "npm-package-arg": "^8.0.1",
+        "npm-packlist": "^2.1.4",
+        "npm-pick-manifest": "^6.0.0",
+        "npm-registry-fetch": "^9.0.0",
+        "promise-retry": "^1.1.1",
+        "read-package-json-fast": "^1.1.3",
+        "rimraf": "^3.0.2",
+        "ssri": "^8.0.0",
+        "tar": "^6.1.0"
+      },
+      "bin": {
+        "pacote": "lib/bin.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/pacote/node_modules/mkdirp": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+      "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+      "dev": true,
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/pako": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
+      "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
+      "dev": true
+    },
+    "node_modules/parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dev": true,
+      "dependencies": {
+        "callsites": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/parse-json": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.0.0",
+        "error-ex": "^1.3.1",
+        "json-parse-even-better-errors": "^2.3.0",
+        "lines-and-columns": "^1.1.6"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/parse-node-version": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz",
+      "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/parse5": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
+      "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
+      "optional": true
+    },
+    "node_modules/parse5-html-rewriting-stream": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz",
+      "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==",
+      "dev": true,
+      "dependencies": {
+        "entities": "^4.3.0",
+        "parse5": "^7.0.0",
+        "parse5-sax-parser": "^7.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
+    "node_modules/parse5-html-rewriting-stream/node_modules/entities": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
+      "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/parse5-html-rewriting-stream/node_modules/parse5": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
+      "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
+      "dev": true,
+      "dependencies": {
+        "entities": "^4.4.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
+    "node_modules/parse5-htmlparser2-tree-adapter": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz",
+      "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==",
+      "dev": true,
+      "dependencies": {
+        "parse5": "^6.0.1"
+      }
+    },
+    "node_modules/parse5-htmlparser2-tree-adapter/node_modules/parse5": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
+      "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
+      "dev": true
+    },
+    "node_modules/parse5-sax-parser": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz",
+      "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==",
+      "dev": true,
+      "dependencies": {
+        "parse5": "^7.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
+    "node_modules/parse5-sax-parser/node_modules/entities": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
+      "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/parse5-sax-parser/node_modules/parse5": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
+      "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
+      "dev": true,
+      "dependencies": {
+        "entities": "^4.4.0"
+      },
+      "funding": {
+        "url": "https://github.com/inikulin/parse5?sponsor=1"
+      }
+    },
+    "node_modules/parseurl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/path-exists": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/path-key": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
+    },
+    "node_modules/path-to-regexp": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+      "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==",
+      "dev": true
+    },
+    "node_modules/path-type": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/performance-now": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+      "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
+      "dev": true
+    },
+    "node_modules/picocolors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/pify": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+      "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+      "dev": true,
+      "optional": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/piscina": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz",
+      "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==",
+      "dev": true,
+      "dependencies": {
+        "eventemitter-asyncresource": "^1.0.0",
+        "hdr-histogram-js": "^2.0.1",
+        "hdr-histogram-percentiles-obj": "^3.0.0"
+      },
+      "optionalDependencies": {
+        "nice-napi": "^1.0.2"
+      }
+    },
+    "node_modules/pkg-dir": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+      "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
+      "dev": true,
+      "dependencies": {
+        "find-up": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/postcss": {
+      "version": "8.4.21",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz",
+      "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        }
+      ],
+      "dependencies": {
+        "nanoid": "^3.3.4",
+        "picocolors": "^1.0.0",
+        "source-map-js": "^1.0.2"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/postcss-loader": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.2.tgz",
+      "integrity": "sha512-fUJzV/QH7NXUAqV8dWJ9Lg4aTkDCezpTS5HgJ2DvqznexTbSTxgi/dTECvTZ15BwKTtk8G/bqI/QTu2HPd3ZCg==",
+      "dev": true,
+      "dependencies": {
+        "cosmiconfig": "^7.0.0",
+        "klona": "^2.0.5",
+        "semver": "^7.3.8"
+      },
+      "engines": {
+        "node": ">= 14.15.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      },
+      "peerDependencies": {
+        "postcss": "^7.0.0 || ^8.0.1",
+        "webpack": "^5.0.0"
+      }
+    },
+    "node_modules/postcss-loader/node_modules/semver": {
+      "version": "7.3.8",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+      "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/postcss-modules-extract-imports": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
+      "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
+      "dev": true,
+      "engines": {
+        "node": "^10 || ^12 || >= 14"
+      },
+      "peerDependencies": {
+        "postcss": "^8.1.0"
+      }
+    },
+    "node_modules/postcss-modules-local-by-default": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz",
+      "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==",
+      "dev": true,
+      "dependencies": {
+        "icss-utils": "^5.0.0",
+        "postcss-selector-parser": "^6.0.2",
+        "postcss-value-parser": "^4.1.0"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >= 14"
+      },
+      "peerDependencies": {
+        "postcss": "^8.1.0"
+      }
+    },
+    "node_modules/postcss-modules-scope": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz",
+      "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==",
+      "dev": true,
+      "dependencies": {
+        "postcss-selector-parser": "^6.0.4"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >= 14"
+      },
+      "peerDependencies": {
+        "postcss": "^8.1.0"
+      }
+    },
+    "node_modules/postcss-modules-values": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz",
+      "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==",
+      "dev": true,
+      "dependencies": {
+        "icss-utils": "^5.0.0"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >= 14"
+      },
+      "peerDependencies": {
+        "postcss": "^8.1.0"
+      }
+    },
+    "node_modules/postcss-selector-parser": {
+      "version": "6.0.11",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz",
+      "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==",
+      "dev": true,
+      "dependencies": {
+        "cssesc": "^3.0.0",
+        "util-deprecate": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/postcss-value-parser": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+      "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+      "dev": true
+    },
+    "node_modules/pretty-bytes": {
+      "version": "5.6.0",
+      "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
+      "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/process-nextick-args": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+      "dev": true
+    },
+    "node_modules/promise-inflight": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz",
+      "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=",
+      "dev": true
+    },
+    "node_modules/promise-retry": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz",
+      "integrity": "sha512-StEy2osPr28o17bIW776GtwO6+Q+M9zPiZkYfosciUUMYqjhU/ffwRAH0zN2+uvGyUsn8/YICIHRzLbPacpZGw==",
+      "dev": true,
+      "dependencies": {
+        "err-code": "^1.0.0",
+        "retry": "^0.10.0"
+      },
+      "engines": {
+        "node": ">=0.12"
+      }
+    },
+    "node_modules/proxy-addr": {
+      "version": "2.0.7",
+      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+      "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+      "dev": true,
+      "dependencies": {
+        "forwarded": "0.2.0",
+        "ipaddr.js": "1.9.1"
+      },
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/proxy-addr/node_modules/ipaddr.js": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+      "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.10"
+      }
+    },
+    "node_modules/prr": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
+      "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==",
+      "dev": true,
+      "optional": true
+    },
+    "node_modules/psl": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
+      "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==",
+      "dev": true
+    },
+    "node_modules/punycode": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
+      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/qs": {
+      "version": "6.11.0",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+      "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
+      "dev": true,
+      "dependencies": {
+        "side-channel": "^1.0.4"
+      },
+      "engines": {
+        "node": ">=0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/randombytes": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "^5.1.0"
+      }
+    },
+    "node_modules/range-parser": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+      "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/raw-body": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
+      "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
+      "dev": true,
+      "dependencies": {
+        "bytes": "3.1.2",
+        "http-errors": "2.0.0",
+        "iconv-lite": "0.4.24",
+        "unpipe": "1.0.0"
+      },
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/raw-body/node_modules/bytes": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+      "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/read-package-json-fast": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-1.2.2.tgz",
+      "integrity": "sha512-39DbPJjkltEzfXJXB6D8/Ir3GFOU2YbSKa2HaB/Y3nKrc/zY+0XrALpID6/13ezWyzqvOHrBbR4t4cjQuTdBVQ==",
+      "dev": true,
+      "dependencies": {
+        "json-parse-even-better-errors": "^2.3.0",
+        "npm-normalize-package-bin": "^1.0.1"
+      }
+    },
+    "node_modules/readable-stream": {
+      "version": "2.3.7",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
+      "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
+      "dev": true,
+      "dependencies": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.3",
+        "isarray": "~1.0.0",
+        "process-nextick-args": "~2.0.0",
+        "safe-buffer": "~5.1.1",
+        "string_decoder": "~1.1.1",
+        "util-deprecate": "~1.0.1"
+      }
+    },
+    "node_modules/readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "dependencies": {
+        "picomatch": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
+    "node_modules/reflect-metadata": {
+      "version": "0.1.13",
+      "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
+      "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg=="
+    },
+    "node_modules/regenerate": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
+      "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==",
+      "dev": true
+    },
+    "node_modules/regenerate-unicode-properties": {
+      "version": "10.1.0",
+      "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz",
+      "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==",
+      "dev": true,
+      "dependencies": {
+        "regenerate": "^1.4.2"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/regenerator-runtime": {
+      "version": "0.13.11",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+      "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
+      "dev": true
+    },
+    "node_modules/regenerator-transform": {
+      "version": "0.15.1",
+      "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz",
+      "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==",
+      "dev": true,
+      "dependencies": {
+        "@babel/runtime": "^7.8.4"
+      }
+    },
+    "node_modules/regex-parser": {
+      "version": "2.2.11",
+      "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz",
+      "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==",
+      "dev": true
+    },
+    "node_modules/regexpu-core": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.0.tgz",
+      "integrity": "sha512-ZdhUQlng0RoscyW7jADnUZ25F5eVtHdMyXSb2PiwafvteRAOJUjFoUPEYZSIfP99fBIs3maLIRfpEddT78wAAQ==",
+      "dev": true,
+      "dependencies": {
+        "@babel/regjsgen": "^0.8.0",
+        "regenerate": "^1.4.2",
+        "regenerate-unicode-properties": "^10.1.0",
+        "regjsparser": "^0.9.1",
+        "unicode-match-property-ecmascript": "^2.0.0",
+        "unicode-match-property-value-ecmascript": "^2.1.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/regjsparser": {
+      "version": "0.9.1",
+      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz",
+      "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==",
+      "dev": true,
+      "dependencies": {
+        "jsesc": "~0.5.0"
+      },
+      "bin": {
+        "regjsparser": "bin/parser"
+      }
+    },
+    "node_modules/regjsparser/node_modules/jsesc": {
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
+      "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==",
+      "dev": true,
+      "bin": {
+        "jsesc": "bin/jsesc"
+      }
+    },
+    "node_modules/request": {
+      "version": "2.88.2",
+      "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
+      "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
+      "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142",
+      "dev": true,
+      "dependencies": {
+        "aws-sign2": "~0.7.0",
+        "aws4": "^1.8.0",
+        "caseless": "~0.12.0",
+        "combined-stream": "~1.0.6",
+        "extend": "~3.0.2",
+        "forever-agent": "~0.6.1",
+        "form-data": "~2.3.2",
+        "har-validator": "~5.1.3",
+        "http-signature": "~1.2.0",
+        "is-typedarray": "~1.0.0",
+        "isstream": "~0.1.2",
+        "json-stringify-safe": "~5.0.1",
+        "mime-types": "~2.1.19",
+        "oauth-sign": "~0.9.0",
+        "performance-now": "^2.1.0",
+        "qs": "~6.5.2",
+        "safe-buffer": "^5.1.2",
+        "tough-cookie": "~2.5.0",
+        "tunnel-agent": "^0.6.0",
+        "uuid": "^3.3.2"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/request/node_modules/qs": {
+      "version": "6.5.3",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
+      "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/require-directory": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/require-from-string": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+      "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/requires-port": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+      "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
+      "dev": true
+    },
+    "node_modules/resolve": {
+      "version": "1.19.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz",
+      "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==",
+      "dependencies": {
+        "is-core-module": "^2.1.0",
+        "path-parse": "^1.0.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/resolve-from": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+      "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/resolve-url-loader": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz",
+      "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==",
+      "dev": true,
+      "dependencies": {
+        "adjust-sourcemap-loader": "^4.0.0",
+        "convert-source-map": "^1.7.0",
+        "loader-utils": "^2.0.0",
+        "postcss": "^8.2.14",
+        "source-map": "0.6.1"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/resolve-url-loader/node_modules/loader-utils": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
+      "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
+      "dev": true,
+      "dependencies": {
+        "big.js": "^5.2.2",
+        "emojis-list": "^3.0.0",
+        "json5": "^2.1.2"
+      },
+      "engines": {
+        "node": ">=8.9.0"
+      }
+    },
+    "node_modules/resolve-url-loader/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/restore-cursor": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
+      "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
+      "dev": true,
+      "dependencies": {
+        "onetime": "^5.1.0",
+        "signal-exit": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/retry": {
+      "version": "0.10.1",
+      "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz",
+      "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=",
+      "dev": true,
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/reusify": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+      "dev": true,
+      "engines": {
+        "iojs": ">=1.0.0",
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/rimraf": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+      "dev": true,
+      "dependencies": {
+        "glob": "^7.1.3"
+      },
+      "bin": {
+        "rimraf": "bin.js"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/rimraf/node_modules/glob": {
+      "version": "7.1.6",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
+      "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+      "dev": true,
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/run-async": {
+      "version": "2.4.1",
+      "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
+      "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
+    "node_modules/rxjs": {
+      "version": "6.6.3",
+      "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz",
+      "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==",
+      "dependencies": {
+        "tslib": "^1.9.0"
+      },
+      "engines": {
+        "npm": ">=2.0.0"
+      }
+    },
+    "node_modules/rxjs-compat": {
+      "version": "6.5.3",
+      "resolved": "https://registry.npmjs.org/rxjs-compat/-/rxjs-compat-6.5.3.tgz",
+      "integrity": "sha512-BIJX2yovz3TBpjJoAZyls2QYuU6ZiCaZ+U96SmxQpuSP/qDUfiXPKOVLbThBB2WZijNHkdTTJXKRwvv5Y48H7g=="
+    },
+    "node_modules/rxjs/node_modules/tslib": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+    },
+    "node_modules/safe-buffer": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+    },
+    "node_modules/safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
+      "dev": true
+    },
+    "node_modules/sass": {
+      "version": "1.58.1",
+      "resolved": "https://registry.npmjs.org/sass/-/sass-1.58.1.tgz",
+      "integrity": "sha512-bnINi6nPXbP1XNRaranMFEBZWUfdW/AF16Ql5+ypRxfTvCRTTKrLsMIakyDcayUt2t/RZotmL4kgJwNH5xO+bg==",
+      "dev": true,
+      "dependencies": {
+        "chokidar": ">=3.0.0 <4.0.0",
+        "immutable": "^4.0.0",
+        "source-map-js": ">=0.6.2 <2.0.0"
+      },
+      "bin": {
+        "sass": "sass.js"
+      },
+      "engines": {
+        "node": ">=12.0.0"
+      }
+    },
+    "node_modules/sass-loader": {
+      "version": "13.2.0",
+      "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.2.0.tgz",
+      "integrity": "sha512-JWEp48djQA4nbZxmgC02/Wh0eroSUutulROUusYJO9P9zltRbNN80JCBHqRGzjd4cmZCa/r88xgfkjGD0TXsHg==",
+      "dev": true,
+      "dependencies": {
+        "klona": "^2.0.4",
+        "neo-async": "^2.6.2"
+      },
+      "engines": {
+        "node": ">= 14.15.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      },
+      "peerDependencies": {
+        "fibers": ">= 3.1.0",
+        "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
+        "sass": "^1.3.0",
+        "sass-embedded": "*",
+        "webpack": "^5.0.0"
+      },
+      "peerDependenciesMeta": {
+        "fibers": {
+          "optional": true
+        },
+        "node-sass": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        },
+        "sass-embedded": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/sax": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+      "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
+      "dev": true,
+      "optional": true
+    },
+    "node_modules/schema-utils": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz",
+      "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==",
+      "dev": true,
+      "dependencies": {
+        "@types/json-schema": "^7.0.9",
+        "ajv": "^8.8.0",
+        "ajv-formats": "^2.1.1",
+        "ajv-keywords": "^5.0.0"
+      },
+      "engines": {
+        "node": ">= 12.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      }
+    },
+    "node_modules/schema-utils/node_modules/ajv": {
+      "version": "8.12.0",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+      "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+      "dev": true,
+      "dependencies": {
+        "fast-deep-equal": "^3.1.1",
+        "json-schema-traverse": "^1.0.0",
+        "require-from-string": "^2.0.2",
+        "uri-js": "^4.2.2"
+      },
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/epoberezkin"
+      }
+    },
+    "node_modules/schema-utils/node_modules/ajv-keywords": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+      "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+      "dev": true,
+      "dependencies": {
+        "fast-deep-equal": "^3.1.3"
+      },
+      "peerDependencies": {
+        "ajv": "^8.8.2"
+      }
+    },
+    "node_modules/schema-utils/node_modules/json-schema-traverse": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+      "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+      "dev": true
+    },
+    "node_modules/select-hose": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
+      "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==",
+      "dev": true
+    },
+    "node_modules/selfsigned": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz",
+      "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==",
+      "dev": true,
+      "dependencies": {
+        "node-forge": "^1"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/semver": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+      "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
+      "bin": {
+        "semver": "bin/semver"
+      }
+    },
+    "node_modules/semver-dsl": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz",
+      "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=",
+      "dev": true,
+      "dependencies": {
+        "semver": "^5.3.0"
+      }
+    },
+    "node_modules/semver-intersect": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.4.0.tgz",
+      "integrity": "sha512-d8fvGg5ycKAq0+I6nfWeCx6ffaWJCsBYU0H2Rq56+/zFePYfT8mXkB3tWBSjR5BerkHNZ5eTPIk1/LBYas35xQ==",
+      "dev": true,
+      "dependencies": {
+        "semver": "^5.0.0"
+      }
+    },
+    "node_modules/send": {
+      "version": "0.18.0",
+      "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+      "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
+      "dev": true,
+      "dependencies": {
+        "debug": "2.6.9",
+        "depd": "2.0.0",
+        "destroy": "1.2.0",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "fresh": "0.5.2",
+        "http-errors": "2.0.0",
+        "mime": "1.6.0",
+        "ms": "2.1.3",
+        "on-finished": "2.4.1",
+        "range-parser": "~1.2.1",
+        "statuses": "2.0.1"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/send/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/send/node_modules/debug/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true
+    },
+    "node_modules/send/node_modules/depd": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+      "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/send/node_modules/ms": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+      "dev": true
+    },
+    "node_modules/serialize-javascript": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
+      "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
+      "dev": true,
+      "dependencies": {
+        "randombytes": "^2.1.0"
+      }
+    },
+    "node_modules/serve-index": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
+      "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==",
+      "dev": true,
+      "dependencies": {
+        "accepts": "~1.3.4",
+        "batch": "0.6.1",
+        "debug": "2.6.9",
+        "escape-html": "~1.0.3",
+        "http-errors": "~1.6.2",
+        "mime-types": "~2.1.17",
+        "parseurl": "~1.3.2"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/serve-index/node_modules/debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "dev": true,
+      "dependencies": {
+        "ms": "2.0.0"
+      }
+    },
+    "node_modules/serve-index/node_modules/http-errors": {
+      "version": "1.6.3",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
+      "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==",
+      "dev": true,
+      "dependencies": {
+        "depd": "~1.1.2",
+        "inherits": "2.0.3",
+        "setprototypeof": "1.1.0",
+        "statuses": ">= 1.4.0 < 2"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/serve-index/node_modules/inherits": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+      "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
+      "dev": true
+    },
+    "node_modules/serve-index/node_modules/ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
+      "dev": true
+    },
+    "node_modules/serve-index/node_modules/setprototypeof": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
+      "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
+      "dev": true
+    },
+    "node_modules/serve-index/node_modules/statuses": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+      "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/serve-static": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+      "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
+      "dev": true,
+      "dependencies": {
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "parseurl": "~1.3.3",
+        "send": "0.18.0"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/set-blocking": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+      "dev": true
+    },
+    "node_modules/setprototypeof": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+      "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
+      "dev": true
+    },
+    "node_modules/shallow-clone": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
+      "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
+      "dev": true,
+      "dependencies": {
+        "kind-of": "^6.0.2"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shebang-command": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
+      "dev": true,
+      "dependencies": {
+        "shebang-regex": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/shebang-regex": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/side-channel": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+      "dev": true,
+      "dependencies": {
+        "call-bind": "^1.0.0",
+        "get-intrinsic": "^1.0.2",
+        "object-inspect": "^1.9.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/signal-exit": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
+      "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
+      "dev": true
+    },
+    "node_modules/sirv": {
+      "version": "1.0.19",
+      "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz",
+      "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==",
+      "dev": true,
+      "dependencies": {
+        "@polka/url": "^1.0.0-next.20",
+        "mrmime": "^1.0.0",
+        "totalist": "^1.0.0"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/slash": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz",
+      "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==",
+      "dev": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/smart-buffer": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
+      "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 6.0.0",
+        "npm": ">= 3.0.0"
+      }
+    },
+    "node_modules/sockjs": {
+      "version": "0.3.24",
+      "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
+      "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==",
+      "dev": true,
+      "dependencies": {
+        "faye-websocket": "^0.11.3",
+        "uuid": "^8.3.2",
+        "websocket-driver": "^0.7.4"
+      }
+    },
+    "node_modules/sockjs/node_modules/uuid": {
+      "version": "8.3.2",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+      "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+      "dev": true,
+      "bin": {
+        "uuid": "dist/bin/uuid"
+      }
+    },
+    "node_modules/socks": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz",
+      "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==",
+      "dev": true,
+      "dependencies": {
+        "ip": "^1.1.5",
+        "smart-buffer": "^4.2.0"
+      },
+      "engines": {
+        "node": ">= 10.13.0",
+        "npm": ">= 3.0.0"
+      }
+    },
+    "node_modules/socks-proxy-agent": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz",
+      "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==",
+      "dev": true,
+      "dependencies": {
+        "agent-base": "^6.0.2",
+        "debug": "4",
+        "socks": "^2.3.3"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "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/source-map-js": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+      "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-loader": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.1.tgz",
+      "integrity": "sha512-oqXpzDIByKONVY8g1NUPOTQhe0UTU5bWUl32GSkqK2LjJj0HmwTMVKxcUip0RgAYhY1mqgOxjbQM48a0mmeNfA==",
+      "dev": true,
+      "dependencies": {
+        "abab": "^2.0.6",
+        "iconv-lite": "^0.6.3",
+        "source-map-js": "^1.0.2"
+      },
+      "engines": {
+        "node": ">= 14.15.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      },
+      "peerDependencies": {
+        "webpack": "^5.72.1"
+      }
+    },
+    "node_modules/source-map-loader/node_modules/iconv-lite": {
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+      "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+      "dev": true,
+      "dependencies": {
+        "safer-buffer": ">= 2.1.2 < 3.0.0"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/source-map-support": {
+      "version": "0.5.21",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+      "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
+      "dev": true,
+      "dependencies": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      }
+    },
+    "node_modules/source-map-support/node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/sourcemap-codec": {
+      "version": "1.4.8",
+      "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
+      "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="
+    },
+    "node_modules/spdy": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz",
+      "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==",
+      "dev": true,
+      "dependencies": {
+        "debug": "^4.1.0",
+        "handle-thing": "^2.0.0",
+        "http-deceiver": "^1.2.7",
+        "select-hose": "^2.0.0",
+        "spdy-transport": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/spdy-transport": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz",
+      "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==",
+      "dev": true,
+      "dependencies": {
+        "debug": "^4.1.0",
+        "detect-node": "^2.0.4",
+        "hpack.js": "^2.1.6",
+        "obuf": "^1.1.2",
+        "readable-stream": "^3.0.6",
+        "wbuf": "^1.7.3"
+      }
+    },
+    "node_modules/spdy-transport/node_modules/readable-stream": {
+      "version": "3.6.2",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+      "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+      "dev": true,
+      "dependencies": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
+      "dev": true
+    },
+    "node_modules/sshpk": {
+      "version": "1.16.1",
+      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
+      "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
+      "dev": true,
+      "dependencies": {
+        "asn1": "~0.2.3",
+        "assert-plus": "^1.0.0",
+        "bcrypt-pbkdf": "^1.0.0",
+        "dashdash": "^1.12.0",
+        "ecc-jsbn": "~0.1.1",
+        "getpass": "^0.1.1",
+        "jsbn": "~0.1.0",
+        "safer-buffer": "^2.0.2",
+        "tweetnacl": "~0.14.0"
+      },
+      "bin": {
+        "sshpk-conv": "bin/sshpk-conv",
+        "sshpk-sign": "bin/sshpk-sign",
+        "sshpk-verify": "bin/sshpk-verify"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/ssri": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz",
+      "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==",
+      "dev": true,
+      "dependencies": {
+        "minipass": "^3.1.1"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/statuses": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
+      "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "~5.1.0"
+      }
+    },
+    "node_modules/string-width": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
+      "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
+      "dependencies": {
+        "emoji-regex": "^8.0.0",
+        "is-fullwidth-code-point": "^3.0.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-ansi": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
+      "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
+      "dependencies": {
+        "ansi-regex": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/strip-final-newline": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+      "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/swagger-ui-dist": {
+      "version": "3.52.5",
+      "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.52.5.tgz",
+      "integrity": "sha512-8z18eX8G/jbTXYzyNIaobrnD7PSN7yU/YkSasMmajrXtw0FGS64XjrKn5v37d36qmU3o1xLeuYnktshRr7uIFw=="
+    },
+    "node_modules/symbol-observable": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-3.0.0.tgz",
+      "integrity": "sha512-6tDOXSHiVjuCaasQSWTmHUWn4PuG7qa3+1WT031yTc/swT7+rLiw3GOrFxaH1E3lLP09dH3bVuVDf2gK5rxG3Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/tapable": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
+      "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/tar": {
+      "version": "6.1.11",
+      "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz",
+      "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==",
+      "dev": true,
+      "dependencies": {
+        "chownr": "^2.0.0",
+        "fs-minipass": "^2.0.0",
+        "minipass": "^3.0.0",
+        "minizlib": "^2.1.1",
+        "mkdirp": "^1.0.3",
+        "yallist": "^4.0.0"
+      },
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/tar/node_modules/mkdirp": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+      "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+      "dev": true,
+      "bin": {
+        "mkdirp": "bin/cmd.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/terser": {
+      "version": "5.16.3",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.3.tgz",
+      "integrity": "sha512-v8wWLaS/xt3nE9dgKEWhNUFP6q4kngO5B8eYFUuebsu7Dw/UNAnpUod6UHo04jSSkv8TzKHjZDSd7EXdDQAl8Q==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/source-map": "^0.3.2",
+        "acorn": "^8.5.0",
+        "commander": "^2.20.0",
+        "source-map-support": "~0.5.20"
+      },
+      "bin": {
+        "terser": "bin/terser"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/terser-webpack-plugin": {
+      "version": "5.3.6",
+      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz",
+      "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==",
+      "dev": true,
+      "dependencies": {
+        "@jridgewell/trace-mapping": "^0.3.14",
+        "jest-worker": "^27.4.5",
+        "schema-utils": "^3.1.1",
+        "serialize-javascript": "^6.0.0",
+        "terser": "^5.14.1"
+      },
+      "engines": {
+        "node": ">= 10.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      },
+      "peerDependencies": {
+        "webpack": "^5.1.0"
+      },
+      "peerDependenciesMeta": {
+        "@swc/core": {
+          "optional": true
+        },
+        "esbuild": {
+          "optional": true
+        },
+        "uglify-js": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/terser-webpack-plugin/node_modules/schema-utils": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
+      "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
+      "dev": true,
+      "dependencies": {
+        "@types/json-schema": "^7.0.8",
+        "ajv": "^6.12.5",
+        "ajv-keywords": "^3.5.2"
+      },
+      "engines": {
+        "node": ">= 10.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      }
+    },
+    "node_modules/test-exclude": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
+      "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
+      "dev": true,
+      "dependencies": {
+        "@istanbuljs/schema": "^0.1.2",
+        "glob": "^7.1.4",
+        "minimatch": "^3.0.4"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/test-exclude/node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "dev": true,
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+      "dev": true
+    },
+    "node_modules/through": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
+      "dev": true
+    },
+    "node_modules/thunky": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
+      "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
+      "dev": true
+    },
+    "node_modules/tmp": {
+      "version": "0.0.33",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
+      "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
+      "dev": true,
+      "dependencies": {
+        "os-tmpdir": "~1.0.2"
+      },
+      "engines": {
+        "node": ">=0.6.0"
+      }
+    },
+    "node_modules/to-fast-properties": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
+      "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/toidentifier": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+      "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.6"
+      }
+    },
+    "node_modules/totalist": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz",
+      "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/tough-cookie": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz",
+      "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
+      "dev": true,
+      "dependencies": {
+        "psl": "^1.1.28",
+        "punycode": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.8"
+      }
+    },
+    "node_modules/tree-kill": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
+      "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
+      "dev": true,
+      "bin": {
+        "tree-kill": "cli.js"
+      }
+    },
+    "node_modules/ts-node": {
+      "version": "8.4.1",
+      "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.4.1.tgz",
+      "integrity": "sha512-5LpRN+mTiCs7lI5EtbXmF/HfMeCjzt7DH9CZwtkr6SywStrNQC723wG+aOWFiLNn7zT3kD/RnFqi3ZUfr4l5Qw==",
+      "dev": true,
+      "dependencies": {
+        "arg": "^4.1.0",
+        "diff": "^4.0.1",
+        "make-error": "^1.1.1",
+        "source-map-support": "^0.5.6",
+        "yn": "^3.0.0"
+      },
+      "bin": {
+        "ts-node": "dist/bin.js"
+      },
+      "engines": {
+        "node": ">=4.2.0"
+      },
+      "peerDependencies": {
+        "typescript": ">=2.0"
+      }
+    },
+    "node_modules/tslib": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+      "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
+    },
+    "node_modules/tslint": {
+      "version": "6.1.3",
+      "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz",
+      "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==",
+      "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.",
+      "dev": true,
+      "dependencies": {
+        "@babel/code-frame": "^7.0.0",
+        "builtin-modules": "^1.1.1",
+        "chalk": "^2.3.0",
+        "commander": "^2.12.1",
+        "diff": "^4.0.1",
+        "glob": "^7.1.1",
+        "js-yaml": "^3.13.1",
+        "minimatch": "^3.0.4",
+        "mkdirp": "^0.5.3",
+        "resolve": "^1.3.2",
+        "semver": "^5.3.0",
+        "tslib": "^1.13.0",
+        "tsutils": "^2.29.0"
+      },
+      "bin": {
+        "tslint": "bin/tslint"
+      },
+      "engines": {
+        "node": ">=4.8.0"
+      },
+      "peerDependencies": {
+        "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev"
+      }
+    },
+    "node_modules/tslint/node_modules/tslib": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+      "dev": true
+    },
+    "node_modules/tsutils": {
+      "version": "2.29.0",
+      "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
+      "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
+      "dev": true,
+      "dependencies": {
+        "tslib": "^1.8.1"
+      },
+      "peerDependencies": {
+        "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev"
+      }
+    },
+    "node_modules/tsutils/node_modules/tslib": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+      "dev": true
+    },
+    "node_modules/tunnel-agent": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
+      "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
+      "dev": true,
+      "dependencies": {
+        "safe-buffer": "^5.0.1"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/tweetnacl": {
+      "version": "0.14.5",
+      "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+      "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
+      "dev": true
+    },
+    "node_modules/type-fest": {
+      "version": "0.11.0",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz",
+      "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/type-is": {
+      "version": "1.6.18",
+      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+      "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+      "dev": true,
+      "dependencies": {
+        "media-typer": "0.3.0",
+        "mime-types": "~2.1.24"
+      },
+      "engines": {
+        "node": ">= 0.6"
+      }
+    },
+    "node_modules/typed-assert": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz",
+      "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==",
+      "dev": true
+    },
+    "node_modules/typescript": {
+      "version": "4.1.6",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.6.tgz",
+      "integrity": "sha512-pxnwLxeb/Z5SP80JDRzVjh58KsM6jZHRAOtTpS7sXLS4ogXNKC9ANxHHZqLLeVHZN35jCtI4JdmLLbLiC1kBow==",
+      "bin": {
+        "tsc": "bin/tsc",
+        "tsserver": "bin/tsserver"
+      },
+      "engines": {
+        "node": ">=4.2.0"
+      }
+    },
+    "node_modules/unicode-canonical-property-names-ecmascript": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
+      "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/unicode-match-property-ecmascript": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz",
+      "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==",
+      "dev": true,
+      "dependencies": {
+        "unicode-canonical-property-names-ecmascript": "^2.0.0",
+        "unicode-property-aliases-ecmascript": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/unicode-match-property-value-ecmascript": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz",
+      "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/unicode-property-aliases-ecmascript": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz",
+      "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/unique-filename": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
+      "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==",
+      "dev": true,
+      "dependencies": {
+        "unique-slug": "^2.0.0"
+      }
+    },
+    "node_modules/unique-slug": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz",
+      "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==",
+      "dev": true,
+      "dependencies": {
+        "imurmurhash": "^0.1.4"
+      }
+    },
+    "node_modules/universal-analytics": {
+      "version": "0.4.23",
+      "resolved": "https://registry.npmjs.org/universal-analytics/-/universal-analytics-0.4.23.tgz",
+      "integrity": "sha512-lgMIH7XBI6OgYn1woDEmxhGdj8yDefMKg7GkWdeATAlQZFrMrNyxSkpDzY57iY0/6fdlzTbBV03OawvvzG+q7A==",
+      "dev": true,
+      "dependencies": {
+        "debug": "^4.1.1",
+        "request": "^2.88.2",
+        "uuid": "^3.0.0"
+      }
+    },
+    "node_modules/universalify": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+      "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+      "engines": {
+        "node": ">= 4.0.0"
+      }
+    },
+    "node_modules/unpipe": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+      "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/update-browserslist-db": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
+      "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        }
+      ],
+      "dependencies": {
+        "escalade": "^3.1.1",
+        "picocolors": "^1.0.0"
+      },
+      "bin": {
+        "browserslist-lint": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
+    "node_modules/uri-js": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
+      "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==",
+      "dev": true,
+      "dependencies": {
+        "punycode": "^2.1.0"
+      }
+    },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
+      "dev": true
+    },
+    "node_modules/utils-merge": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+      "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/uuid": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
+      "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
+      "deprecated": "Please upgrade  to version 7 or higher.  Older versions may use Math.random() in certain circumstances, which is known to be problematic.  See https://v8.dev/blog/math-random for details.",
+      "dev": true,
+      "bin": {
+        "uuid": "bin/uuid"
+      }
+    },
+    "node_modules/validate-npm-package-name": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz",
+      "integrity": "sha1-X6kS2B630MdK/BQN5zF/DKffQ34=",
+      "dev": true,
+      "dependencies": {
+        "builtins": "^1.0.3"
+      }
+    },
+    "node_modules/vary": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+      "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/verror": {
+      "version": "1.10.0",
+      "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
+      "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
+      "dev": true,
+      "engines": [
+        "node >=0.6.0"
+      ],
+      "dependencies": {
+        "assert-plus": "^1.0.0",
+        "core-util-is": "1.0.2",
+        "extsprintf": "^1.2.0"
+      }
+    },
+    "node_modules/watchpack": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
+      "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
+      "dev": true,
+      "dependencies": {
+        "glob-to-regexp": "^0.4.1",
+        "graceful-fs": "^4.1.2"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/wbuf": {
+      "version": "1.7.3",
+      "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz",
+      "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==",
+      "dev": true,
+      "dependencies": {
+        "minimalistic-assert": "^1.0.0"
+      }
+    },
+    "node_modules/wcwidth": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
+      "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=",
+      "dev": true,
+      "dependencies": {
+        "defaults": "^1.0.3"
+      }
+    },
+    "node_modules/web-animations-js": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/web-animations-js/-/web-animations-js-2.3.2.tgz",
+      "integrity": "sha512-TOMFWtQdxzjWp8qx4DAraTWTsdhxVSiWa6NkPFSaPtZ1diKUxTn4yTix73A1euG1WbSOMMPcY51cnjTIHrGtDA=="
+    },
+    "node_modules/webpack": {
+      "version": "5.76.1",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz",
+      "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==",
+      "dev": true,
+      "dependencies": {
+        "@types/eslint-scope": "^3.7.3",
+        "@types/estree": "^0.0.51",
+        "@webassemblyjs/ast": "1.11.1",
+        "@webassemblyjs/wasm-edit": "1.11.1",
+        "@webassemblyjs/wasm-parser": "1.11.1",
+        "acorn": "^8.7.1",
+        "acorn-import-assertions": "^1.7.6",
+        "browserslist": "^4.14.5",
+        "chrome-trace-event": "^1.0.2",
+        "enhanced-resolve": "^5.10.0",
+        "es-module-lexer": "^0.9.0",
+        "eslint-scope": "5.1.1",
+        "events": "^3.2.0",
+        "glob-to-regexp": "^0.4.1",
+        "graceful-fs": "^4.2.9",
+        "json-parse-even-better-errors": "^2.3.1",
+        "loader-runner": "^4.2.0",
+        "mime-types": "^2.1.27",
+        "neo-async": "^2.6.2",
+        "schema-utils": "^3.1.0",
+        "tapable": "^2.1.1",
+        "terser-webpack-plugin": "^5.1.3",
+        "watchpack": "^2.4.0",
+        "webpack-sources": "^3.2.3"
+      },
+      "bin": {
+        "webpack": "bin/webpack.js"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      },
+      "peerDependenciesMeta": {
+        "webpack-cli": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/webpack-bundle-analyzer": {
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz",
+      "integrity": "sha512-j9b8ynpJS4K+zfO5GGwsAcQX4ZHpWV+yRiHDiL+bE0XHJ8NiPYLTNVQdlFYWxtpg9lfAQNlwJg16J9AJtFSXRg==",
+      "dev": true,
+      "dependencies": {
+        "acorn": "^8.0.4",
+        "acorn-walk": "^8.0.0",
+        "chalk": "^4.1.0",
+        "commander": "^7.2.0",
+        "gzip-size": "^6.0.0",
+        "lodash": "^4.17.20",
+        "opener": "^1.5.2",
+        "sirv": "^1.0.7",
+        "ws": "^7.3.1"
+      },
+      "bin": {
+        "webpack-bundle-analyzer": "lib/bin/analyzer.js"
+      },
+      "engines": {
+        "node": ">= 10.13.0"
+      }
+    },
+    "node_modules/webpack-bundle-analyzer/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dev": true,
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/webpack-bundle-analyzer/node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dev": true,
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/webpack-bundle-analyzer/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dev": true,
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/webpack-bundle-analyzer/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+      "dev": true
+    },
+    "node_modules/webpack-bundle-analyzer/node_modules/commander": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+      "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+      "dev": true,
+      "engines": {
+        "node": ">= 10"
+      }
+    },
+    "node_modules/webpack-bundle-analyzer/node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/webpack-bundle-analyzer/node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dev": true,
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/webpack-bundle-analyzer/node_modules/ws": {
+      "version": "7.5.9",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
+      "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=8.3.0"
+      },
+      "peerDependencies": {
+        "bufferutil": "^4.0.1",
+        "utf-8-validate": "^5.0.2"
+      },
+      "peerDependenciesMeta": {
+        "bufferutil": {
+          "optional": true
+        },
+        "utf-8-validate": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/webpack-dev-middleware": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.0.1.tgz",
+      "integrity": "sha512-PZPZ6jFinmqVPJZbisfggDiC+2EeGZ1ZByyMP5sOFJcPPWSexalISz+cvm+j+oYPT7FIJyxT76esjnw9DhE5sw==",
+      "dev": true,
+      "dependencies": {
+        "colorette": "^2.0.10",
+        "memfs": "^3.4.12",
+        "mime-types": "^2.1.31",
+        "range-parser": "^1.2.1",
+        "schema-utils": "^4.0.0"
+      },
+      "engines": {
+        "node": ">= 14.15.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      },
+      "peerDependencies": {
+        "webpack": "^5.0.0"
+      }
+    },
+    "node_modules/webpack-dev-server": {
+      "version": "4.11.1",
+      "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz",
+      "integrity": "sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==",
+      "dev": true,
+      "dependencies": {
+        "@types/bonjour": "^3.5.9",
+        "@types/connect-history-api-fallback": "^1.3.5",
+        "@types/express": "^4.17.13",
+        "@types/serve-index": "^1.9.1",
+        "@types/serve-static": "^1.13.10",
+        "@types/sockjs": "^0.3.33",
+        "@types/ws": "^8.5.1",
+        "ansi-html-community": "^0.0.8",
+        "bonjour-service": "^1.0.11",
+        "chokidar": "^3.5.3",
+        "colorette": "^2.0.10",
+        "compression": "^1.7.4",
+        "connect-history-api-fallback": "^2.0.0",
+        "default-gateway": "^6.0.3",
+        "express": "^4.17.3",
+        "graceful-fs": "^4.2.6",
+        "html-entities": "^2.3.2",
+        "http-proxy-middleware": "^2.0.3",
+        "ipaddr.js": "^2.0.1",
+        "open": "^8.0.9",
+        "p-retry": "^4.5.0",
+        "rimraf": "^3.0.2",
+        "schema-utils": "^4.0.0",
+        "selfsigned": "^2.1.1",
+        "serve-index": "^1.9.1",
+        "sockjs": "^0.3.24",
+        "spdy": "^4.0.2",
+        "webpack-dev-middleware": "^5.3.1",
+        "ws": "^8.4.2"
+      },
+      "bin": {
+        "webpack-dev-server": "bin/webpack-dev-server.js"
+      },
+      "engines": {
+        "node": ">= 12.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      },
+      "peerDependencies": {
+        "webpack": "^4.37.0 || ^5.0.0"
+      },
+      "peerDependenciesMeta": {
+        "webpack-cli": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/webpack-dev-server/node_modules/open": {
+      "version": "8.4.2",
+      "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
+      "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
+      "dev": true,
+      "dependencies": {
+        "define-lazy-prop": "^2.0.0",
+        "is-docker": "^2.1.1",
+        "is-wsl": "^2.2.0"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": {
+      "version": "5.3.3",
+      "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz",
+      "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==",
+      "dev": true,
+      "dependencies": {
+        "colorette": "^2.0.10",
+        "memfs": "^3.4.3",
+        "mime-types": "^2.1.31",
+        "range-parser": "^1.2.1",
+        "schema-utils": "^4.0.0"
+      },
+      "engines": {
+        "node": ">= 12.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      },
+      "peerDependencies": {
+        "webpack": "^4.0.0 || ^5.0.0"
+      }
+    },
+    "node_modules/webpack-merge": {
+      "version": "5.8.0",
+      "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz",
+      "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==",
+      "dev": true,
+      "dependencies": {
+        "clone-deep": "^4.0.1",
+        "wildcard": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=10.0.0"
+      }
+    },
+    "node_modules/webpack-sources": {
+      "version": "3.2.3",
+      "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
+      "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
+      "dev": true,
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/webpack-subresource-integrity": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz",
+      "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==",
+      "dev": true,
+      "dependencies": {
+        "typed-assert": "^1.0.8"
+      },
+      "engines": {
+        "node": ">= 12"
+      },
+      "peerDependencies": {
+        "html-webpack-plugin": ">= 5.0.0-beta.1 < 6",
+        "webpack": "^5.12.0"
+      },
+      "peerDependenciesMeta": {
+        "html-webpack-plugin": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/webpack/node_modules/schema-utils": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
+      "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
+      "dev": true,
+      "dependencies": {
+        "@types/json-schema": "^7.0.8",
+        "ajv": "^6.12.5",
+        "ajv-keywords": "^3.5.2"
+      },
+      "engines": {
+        "node": ">= 10.13.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/webpack"
+      }
+    },
+    "node_modules/websocket-driver": {
+      "version": "0.7.4",
+      "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
+      "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
+      "dev": true,
+      "dependencies": {
+        "http-parser-js": ">=0.5.1",
+        "safe-buffer": ">=5.1.0",
+        "websocket-extensions": ">=0.1.1"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/websocket-extensions": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz",
+      "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/which": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
+      "dev": true,
+      "dependencies": {
+        "isexe": "^2.0.0"
+      },
+      "bin": {
+        "node-which": "bin/node-which"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/wide-align": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
+      "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
+      "dev": true,
+      "dependencies": {
+        "string-width": "^1.0.2 || 2 || 3 || 4"
+      }
+    },
+    "node_modules/wildcard": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz",
+      "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==",
+      "dev": true
+    },
+    "node_modules/wrap-ansi": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+      "dependencies": {
+        "ansi-styles": "^4.0.0",
+        "string-width": "^4.1.0",
+        "strip-ansi": "^6.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/wrap-ansi/node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+    },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+    },
+    "node_modules/ws": {
+      "version": "8.13.0",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
+      "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10.0.0"
+      },
+      "peerDependencies": {
+        "bufferutil": "^4.0.1",
+        "utf-8-validate": ">=5.0.2"
+      },
+      "peerDependenciesMeta": {
+        "bufferutil": {
+          "optional": true
+        },
+        "utf-8-validate": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/xhr2": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/xhr2/-/xhr2-0.2.0.tgz",
+      "integrity": "sha512-BDtiD0i2iKPK/S8OAZfpk6tyzEDnKKSjxWHcMBVmh+LuqJ8A32qXTyOx+TVOg2dKvq6zGBq2sgKPkEeRs1qTRA==",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/yallist": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
+      "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
+      "dev": true
+    },
+    "node_modules/yaml": {
+      "version": "1.10.2",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+      "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/yargs": {
+      "version": "16.2.0",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+      "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+      "dependencies": {
+        "cliui": "^7.0.2",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
+        "require-directory": "^2.1.1",
+        "string-width": "^4.2.0",
+        "y18n": "^5.0.5",
+        "yargs-parser": "^20.2.2"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yargs-parser": {
+      "version": "20.2.9",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+      "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yargs/node_modules/y18n": {
+      "version": "5.0.8",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+      "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/yn": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
+      "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/zone.js": {
+      "version": "0.10.3",
+      "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.10.3.tgz",
+      "integrity": "sha512-LXVLVEq0NNOqK/fLJo3d0kfzd4sxwn2/h67/02pjCjfKDxgx1i9QqpvtHD8CrBnSSwMw5+dy11O7FRX5mkO7Cg=="
+    }
+  },
+  "dependencies": {
+    "@ampproject/remapping": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz",
+      "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==",
+      "requires": {
+        "@jridgewell/gen-mapping": "^0.1.0",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      }
+    },
+    "@angular-devkit/architect": {
+      "version": "0.1102.19",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1102.19.tgz",
+      "integrity": "sha512-5Opv6H+XyCkuQvQ1jsxw416YqMDPX3dVonMarFGBPLBe8YEXLRTJ60dvmuLsLpWk6ccTd3XiNT7WEJy4ctDc2Q==",
+      "dev": true,
+      "requires": {
+        "@angular-devkit/core": "11.2.19",
+        "rxjs": "6.6.3"
+      }
+    },
+    "@angular-devkit/build-angular": {
+      "version": "15.2.4",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-15.2.4.tgz",
+      "integrity": "sha512-wt0S4oz0vxuW0/Ak5X0vQ7s7TSPynmktVNJblu9SFRgwCD3kplV2B693F+M6t8eLzSy0UCSbZp9h3Ae8gLEiEw==",
+      "dev": true,
+      "requires": {
+        "@ampproject/remapping": "2.2.0",
+        "@angular-devkit/architect": "0.1502.4",
+        "@angular-devkit/build-webpack": "0.1502.4",
+        "@angular-devkit/core": "15.2.4",
+        "@babel/core": "7.20.12",
+        "@babel/generator": "7.20.14",
+        "@babel/helper-annotate-as-pure": "7.18.6",
+        "@babel/helper-split-export-declaration": "7.18.6",
+        "@babel/plugin-proposal-async-generator-functions": "7.20.7",
+        "@babel/plugin-transform-async-to-generator": "7.20.7",
+        "@babel/plugin-transform-runtime": "7.19.6",
+        "@babel/preset-env": "7.20.2",
+        "@babel/runtime": "7.20.13",
+        "@babel/template": "7.20.7",
+        "@discoveryjs/json-ext": "0.5.7",
+        "@ngtools/webpack": "15.2.4",
+        "ansi-colors": "4.1.3",
+        "autoprefixer": "10.4.13",
+        "babel-loader": "9.1.2",
+        "babel-plugin-istanbul": "6.1.1",
+        "browserslist": "4.21.5",
+        "cacache": "17.0.4",
+        "chokidar": "3.5.3",
+        "copy-webpack-plugin": "11.0.0",
+        "critters": "0.0.16",
+        "css-loader": "6.7.3",
+        "esbuild": "0.17.8",
+        "esbuild-wasm": "0.17.8",
+        "glob": "8.1.0",
+        "https-proxy-agent": "5.0.1",
+        "inquirer": "8.2.4",
+        "jsonc-parser": "3.2.0",
+        "karma-source-map-support": "1.4.0",
+        "less": "4.1.3",
+        "less-loader": "11.1.0",
+        "license-webpack-plugin": "4.0.2",
+        "loader-utils": "3.2.1",
+        "magic-string": "0.29.0",
+        "mini-css-extract-plugin": "2.7.2",
+        "open": "8.4.1",
+        "ora": "5.4.1",
+        "parse5-html-rewriting-stream": "7.0.0",
+        "piscina": "3.2.0",
+        "postcss": "8.4.21",
+        "postcss-loader": "7.0.2",
+        "resolve-url-loader": "5.0.0",
+        "rxjs": "6.6.7",
+        "sass": "1.58.1",
+        "sass-loader": "13.2.0",
+        "semver": "7.3.8",
+        "source-map-loader": "4.0.1",
+        "source-map-support": "0.5.21",
+        "terser": "5.16.3",
+        "text-table": "0.2.0",
+        "tree-kill": "1.2.2",
+        "tslib": "2.5.0",
+        "webpack": "5.76.1",
+        "webpack-dev-middleware": "6.0.1",
+        "webpack-dev-server": "4.11.1",
+        "webpack-merge": "5.8.0",
+        "webpack-subresource-integrity": "5.1.0"
+      },
+      "dependencies": {
+        "@angular-devkit/architect": {
+          "version": "0.1502.4",
+          "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1502.4.tgz",
+          "integrity": "sha512-bDBcaRMBfXFfK9MpvfNO926F1rL0PEw+mveXxq3/SSql+1XP/hrc5TVGwnoim4g6DqsGmu9upS5DyJ6PnL/hHA==",
+          "dev": true,
+          "requires": {
+            "@angular-devkit/core": "15.2.4",
+            "rxjs": "6.6.7"
+          }
+        },
+        "@angular-devkit/core": {
+          "version": "15.2.4",
+          "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.2.4.tgz",
+          "integrity": "sha512-yl+0j1bMwJLKShsyCXw77tbJG8Sd21+itisPLL2MgEpLNAO252kr9zG4TLlFRJyKVftm2l1h78KjqvM5nbOXNg==",
+          "dev": true,
+          "requires": {
+            "ajv": "8.12.0",
+            "ajv-formats": "2.1.1",
+            "jsonc-parser": "3.2.0",
+            "rxjs": "6.6.7",
+            "source-map": "0.7.4"
+          }
+        },
+        "@ngtools/webpack": {
+          "version": "15.2.4",
+          "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-15.2.4.tgz",
+          "integrity": "sha512-cQ7MsRoGJgPOVnpvFgWhygeSe6zJ0ITiUhjmmuOgpNDfYkrgYxN3Ot/qvQefFei+oGZ1JJ9bRb8lcPKL/apoBQ==",
+          "dev": true,
+          "requires": {}
+        },
+        "ajv": {
+          "version": "8.12.0",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+          "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+          "dev": true,
+          "requires": {
+            "fast-deep-equal": "^3.1.1",
+            "json-schema-traverse": "^1.0.0",
+            "require-from-string": "^2.0.2",
+            "uri-js": "^4.2.2"
+          }
+        },
+        "ansi-colors": {
+          "version": "4.1.3",
+          "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
+          "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
+          "dev": true
+        },
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "babel-loader": {
+          "version": "9.1.2",
+          "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.2.tgz",
+          "integrity": "sha512-mN14niXW43tddohGl8HPu5yfQq70iUThvFL/4QzESA7GcZoC0eVOhvWdQ8+3UlSjaDE9MVtsW9mxDY07W7VpVA==",
+          "dev": true,
+          "requires": {
+            "find-cache-dir": "^3.3.2",
+            "schema-utils": "^4.0.0"
+          }
+        },
+        "brace-expansion": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+          "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+          "dev": true,
+          "requires": {
+            "balanced-match": "^1.0.0"
+          }
+        },
+        "cacache": {
+          "version": "17.0.4",
+          "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.0.4.tgz",
+          "integrity": "sha512-Z/nL3gU+zTUjz5pCA5vVjYM8pmaw2kxM7JEiE0fv3w77Wj+sFbi70CrBruUWH0uNcEdvLDixFpgA2JM4F4DBjA==",
+          "dev": true,
+          "requires": {
+            "@npmcli/fs": "^3.1.0",
+            "fs-minipass": "^3.0.0",
+            "glob": "^8.0.1",
+            "lru-cache": "^7.7.1",
+            "minipass": "^4.0.0",
+            "minipass-collect": "^1.0.2",
+            "minipass-flush": "^1.0.5",
+            "minipass-pipeline": "^1.2.4",
+            "p-map": "^4.0.0",
+            "promise-inflight": "^1.0.1",
+            "ssri": "^10.0.0",
+            "tar": "^6.1.11",
+            "unique-filename": "^3.0.0"
+          },
+          "dependencies": {
+            "lru-cache": {
+              "version": "7.14.1",
+              "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.14.1.tgz",
+              "integrity": "sha512-ysxwsnTKdAx96aTRdhDOCQfDgbHnt8SK0KY8SEjO0wHinhWOFTESbjVCMPbU1uGXg/ch4lifqx0wfjOawU2+WA==",
+              "dev": true
+            }
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+          "dev": true
+        },
+        "fs-minipass": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.1.tgz",
+          "integrity": "sha512-MhaJDcFRTuLidHrIttu0RDGyyXs/IYHVmlcxfLAEFIWjc1vdLAkdwT7Ace2u7DbitWC0toKMl5eJZRYNVreIMw==",
+          "dev": true,
+          "requires": {
+            "minipass": "^4.0.0"
+          }
+        },
+        "glob": {
+          "version": "8.1.0",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
+          "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^5.0.1",
+            "once": "^1.3.0"
+          }
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "inquirer": {
+          "version": "8.2.4",
+          "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.4.tgz",
+          "integrity": "sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg==",
+          "dev": true,
+          "requires": {
+            "ansi-escapes": "^4.2.1",
+            "chalk": "^4.1.1",
+            "cli-cursor": "^3.1.0",
+            "cli-width": "^3.0.0",
+            "external-editor": "^3.0.3",
+            "figures": "^3.0.0",
+            "lodash": "^4.17.21",
+            "mute-stream": "0.0.8",
+            "ora": "^5.4.1",
+            "run-async": "^2.4.0",
+            "rxjs": "^7.5.5",
+            "string-width": "^4.1.0",
+            "strip-ansi": "^6.0.0",
+            "through": "^2.3.6",
+            "wrap-ansi": "^7.0.0"
+          },
+          "dependencies": {
+            "rxjs": {
+              "version": "7.8.0",
+              "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.0.tgz",
+              "integrity": "sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==",
+              "dev": true,
+              "requires": {
+                "tslib": "^2.1.0"
+              }
+            }
+          }
+        },
+        "json-schema-traverse": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+          "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+          "dev": true
+        },
+        "jsonc-parser": {
+          "version": "3.2.0",
+          "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
+          "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==",
+          "dev": true
+        },
+        "magic-string": {
+          "version": "0.29.0",
+          "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.29.0.tgz",
+          "integrity": "sha512-WcfidHrDjMY+eLjlU+8OvwREqHwpgCeKVBUpQ3OhYYuvfaYCUgcbuBzappNzZvg/v8onU3oQj+BYpkOJe9Iw4Q==",
+          "dev": true,
+          "requires": {
+            "@jridgewell/sourcemap-codec": "^1.4.13"
+          }
+        },
+        "minimatch": {
+          "version": "5.1.6",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+          "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+          "dev": true,
+          "requires": {
+            "brace-expansion": "^2.0.1"
+          }
+        },
+        "minipass": {
+          "version": "4.0.3",
+          "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.0.3.tgz",
+          "integrity": "sha512-OW2r4sQ0sI+z5ckEt5c1Tri4xTgZwYDxpE54eqWlQloQRoWtXjqt9udJ5Z4dSv7wK+nfFI7FRXyCpBSft+gpFw==",
+          "dev": true
+        },
+        "open": {
+          "version": "8.4.1",
+          "resolved": "https://registry.npmjs.org/open/-/open-8.4.1.tgz",
+          "integrity": "sha512-/4b7qZNhv6Uhd7jjnREh1NjnPxlTq+XNWPG88Ydkj5AILcA5m3ajvcg57pB24EQjKv0dK62XnDqk9c/hkIG5Kg==",
+          "dev": true,
+          "requires": {
+            "define-lazy-prop": "^2.0.0",
+            "is-docker": "^2.1.1",
+            "is-wsl": "^2.2.0"
+          }
+        },
+        "ora": {
+          "version": "5.4.1",
+          "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz",
+          "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==",
+          "dev": true,
+          "requires": {
+            "bl": "^4.1.0",
+            "chalk": "^4.1.0",
+            "cli-cursor": "^3.1.0",
+            "cli-spinners": "^2.5.0",
+            "is-interactive": "^1.0.0",
+            "is-unicode-supported": "^0.1.0",
+            "log-symbols": "^4.1.0",
+            "strip-ansi": "^6.0.0",
+            "wcwidth": "^1.0.1"
+          }
+        },
+        "rxjs": {
+          "version": "6.6.7",
+          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+          "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+          "dev": true,
+          "requires": {
+            "tslib": "^1.9.0"
+          },
+          "dependencies": {
+            "tslib": {
+              "version": "1.14.1",
+              "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+              "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+              "dev": true
+            }
+          }
+        },
+        "semver": {
+          "version": "7.3.8",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+          "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        },
+        "source-map": {
+          "version": "0.7.4",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
+          "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
+          "dev": true
+        },
+        "ssri": {
+          "version": "10.0.1",
+          "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.1.tgz",
+          "integrity": "sha512-WVy6di9DlPOeBWEjMScpNipeSX2jIZBGEn5Uuo8Q7aIuFEuDX0pw8RxcOjlD1TWP4obi24ki7m/13+nFpcbXrw==",
+          "dev": true,
+          "requires": {
+            "minipass": "^4.0.0"
+          }
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        },
+        "tslib": {
+          "version": "2.4.1",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz",
+          "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==",
+          "dev": true
+        },
+        "unique-filename": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz",
+          "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==",
+          "dev": true,
+          "requires": {
+            "unique-slug": "^4.0.0"
+          }
+        },
+        "unique-slug": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz",
+          "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==",
+          "dev": true,
+          "requires": {
+            "imurmurhash": "^0.1.4"
+          }
+        }
+      }
+    },
+    "@angular-devkit/build-webpack": {
+      "version": "0.1502.4",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1502.4.tgz",
+      "integrity": "sha512-Bs/pxcY3517QAVyAalDxJgjc93KWQos+dFdgEQrKxj/VTs1BTYnLbb2M8Y7MoxVnfH4S+qqxGe5B57T+TlB3Eg==",
+      "dev": true,
+      "requires": {
+        "@angular-devkit/architect": "0.1502.4",
+        "rxjs": "6.6.7"
+      },
+      "dependencies": {
+        "@angular-devkit/architect": {
+          "version": "0.1502.4",
+          "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1502.4.tgz",
+          "integrity": "sha512-bDBcaRMBfXFfK9MpvfNO926F1rL0PEw+mveXxq3/SSql+1XP/hrc5TVGwnoim4g6DqsGmu9upS5DyJ6PnL/hHA==",
+          "dev": true,
+          "requires": {
+            "@angular-devkit/core": "15.2.4",
+            "rxjs": "6.6.7"
+          }
+        },
+        "@angular-devkit/core": {
+          "version": "15.2.4",
+          "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-15.2.4.tgz",
+          "integrity": "sha512-yl+0j1bMwJLKShsyCXw77tbJG8Sd21+itisPLL2MgEpLNAO252kr9zG4TLlFRJyKVftm2l1h78KjqvM5nbOXNg==",
+          "dev": true,
+          "requires": {
+            "ajv": "8.12.0",
+            "ajv-formats": "2.1.1",
+            "jsonc-parser": "3.2.0",
+            "rxjs": "6.6.7",
+            "source-map": "0.7.4"
+          }
+        },
+        "ajv": {
+          "version": "8.12.0",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+          "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+          "dev": true,
+          "requires": {
+            "fast-deep-equal": "^3.1.1",
+            "json-schema-traverse": "^1.0.0",
+            "require-from-string": "^2.0.2",
+            "uri-js": "^4.2.2"
+          }
+        },
+        "json-schema-traverse": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+          "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+          "dev": true
+        },
+        "jsonc-parser": {
+          "version": "3.2.0",
+          "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
+          "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==",
+          "dev": true
+        },
+        "rxjs": {
+          "version": "6.6.7",
+          "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz",
+          "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==",
+          "dev": true,
+          "requires": {
+            "tslib": "^1.9.0"
+          }
+        },
+        "source-map": {
+          "version": "0.7.4",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
+          "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
+          "dev": true
+        },
+        "tslib": {
+          "version": "1.14.1",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+          "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+          "dev": true
+        }
+      }
+    },
+    "@angular-devkit/core": {
+      "version": "11.2.19",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-11.2.19.tgz",
+      "integrity": "sha512-kvS0QXDYDatLyf0NYv2sahPYD7kya4g5GpQAV1ddjjLmEVeZssHt+Xfk2tzrkzYzqRMiyspx3HPPrrOnMUAFhQ==",
+      "dev": true,
+      "requires": {
+        "ajv": "6.12.6",
+        "fast-json-stable-stringify": "2.1.0",
+        "magic-string": "0.25.7",
+        "rxjs": "6.6.3",
+        "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==",
+          "dev": true
+        }
+      }
+    },
+    "@angular-devkit/schematics": {
+      "version": "11.2.19",
+      "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-11.2.19.tgz",
+      "integrity": "sha512-jefsjIlaznKxn5+dHSMwvXTO+QKCKtahu/iZoRcdb25JWGXrkj8/quCuj4VeMFY48g/EPjX+9WhDtRl8TjYBiA==",
+      "dev": true,
+      "requires": {
+        "@angular-devkit/core": "11.2.19",
+        "ora": "5.3.0",
+        "rxjs": "6.6.3"
+      }
+    },
+    "@angular/animations": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-11.2.14.tgz",
+      "integrity": "sha512-Heq/nNrCmb3jbkusu+BQszOecfFI/31Oxxj+CDQkqqYpBcswk6bOJLoEE472o+vmgxaXbgeflU9qbIiCQhpMFA==",
+      "requires": {
+        "tslib": "^2.0.0"
+      }
+    },
+    "@angular/cdk": {
+      "version": "10.2.7",
+      "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-10.2.7.tgz",
+      "integrity": "sha512-ZQjDfTRTn7JuAKsf3jiIdU2XBaxxGBi/ZWYv5Pb3HCl6B4PISsIE5VWRhkoUogoAB0MiFHpjnWeIqknJEm11YQ==",
+      "requires": {
+        "parse5": "^5.0.0",
+        "tslib": "^2.0.0"
+      }
+    },
+    "@angular/cli": {
+      "version": "11.2.19",
+      "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-11.2.19.tgz",
+      "integrity": "sha512-B7ZRmcleBF/D6ojt+LOfHE/2Cs3jpHWK/Khho0c2i1jrqLjCTFlgGfK0NKztbFr0lmbhL6Z7Oj4ge3X6dMcSuQ==",
+      "dev": true,
+      "requires": {
+        "@angular-devkit/architect": "0.1102.19",
+        "@angular-devkit/core": "11.2.19",
+        "@angular-devkit/schematics": "11.2.19",
+        "@schematics/angular": "11.2.19",
+        "@schematics/update": "0.1102.19",
+        "@yarnpkg/lockfile": "1.1.0",
+        "ansi-colors": "4.1.1",
+        "debug": "4.3.1",
+        "ini": "2.0.0",
+        "inquirer": "7.3.3",
+        "jsonc-parser": "3.0.0",
+        "npm-package-arg": "8.1.0",
+        "npm-pick-manifest": "6.1.0",
+        "open": "7.4.0",
+        "ora": "5.3.0",
+        "pacote": "11.2.4",
+        "resolve": "1.19.0",
+        "rimraf": "3.0.2",
+        "semver": "7.3.4",
+        "symbol-observable": "3.0.0",
+        "universal-analytics": "0.4.23",
+        "uuid": "8.3.2"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "4.3.1",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
+          "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==",
+          "dev": true,
+          "requires": {
+            "ms": "2.1.2"
+          }
+        },
+        "semver": {
+          "version": "7.3.4",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
+          "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        },
+        "uuid": {
+          "version": "8.3.2",
+          "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+          "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+          "dev": true
+        }
+      }
+    },
+    "@angular/common": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/common/-/common-11.2.14.tgz",
+      "integrity": "sha512-ZSLV/3j7eCTyLf/8g4yBFLWySjiLz3vLJAGWscYoUpnJWMnug1VRu6zoF/COxCbtORgE+Wz6K0uhfS6MziBGVw==",
+      "requires": {
+        "tslib": "^2.0.0"
+      }
+    },
+    "@angular/compiler": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-11.2.14.tgz",
+      "integrity": "sha512-XBOK3HgA+/y6Cz7kOX4zcJYmgJ264XnfcbXUMU2cD7Ac+mbNhLPKohWrEiSWalfcjnpf5gRfufQrQP7lpAGu0A==",
+      "requires": {
+        "tslib": "^2.0.0"
+      }
+    },
+    "@angular/compiler-cli": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-11.2.14.tgz",
+      "integrity": "sha512-A7ltnCp03/EVqK/Q3tVUDsokgz5GHW3dSPGl0Csk7Ys5uBB9ibHTmVt4eiXA4jt0+6Bk+mKxwe5BEDqLvwYFAg==",
+      "requires": {
+        "@babel/core": "^7.8.6",
+        "@babel/types": "^7.8.6",
+        "canonical-path": "1.0.0",
+        "chokidar": "^3.0.0",
+        "convert-source-map": "^1.5.1",
+        "dependency-graph": "^0.7.2",
+        "fs-extra": "4.0.2",
+        "magic-string": "^0.25.0",
+        "minimist": "^1.2.0",
+        "reflect-metadata": "^0.1.2",
+        "semver": "^6.3.0",
+        "source-map": "^0.6.1",
+        "sourcemap-codec": "^1.4.8",
+        "tslib": "^2.0.0",
+        "yargs": "^16.2.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+        },
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+        }
+      }
+    },
+    "@angular/core": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/core/-/core-11.2.14.tgz",
+      "integrity": "sha512-vpR4XqBGitk1Faph37CSpemwIYTmJ3pdIVNoHKP6jLonpWu+0azkchf0f7oD8/2ivj2F81opcIw0tcsy/D/5Vg==",
+      "requires": {
+        "tslib": "^2.0.0"
+      }
+    },
+    "@angular/forms": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-11.2.14.tgz",
+      "integrity": "sha512-4LWqY6KEIk1AZQFnk+4PJSOCamlD4tumuVN06gO4D0dZo9Cx+GcvW6pM6N0CPubRvPs3sScCnu20WT11HNWC1w==",
+      "requires": {
+        "tslib": "^2.0.0"
+      }
+    },
+    "@angular/localize": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-11.2.14.tgz",
+      "integrity": "sha512-ssMuquxxqxA98LgEICEO/3JdmSflWxu5rlm/HPo28bnGiZ4IzDamZjJ1cu4S6RgsonJ1drB3Z8wkidXfEYZiWA==",
+      "requires": {
+        "@babel/core": "7.8.3",
+        "glob": "7.1.2",
+        "yargs": "^16.2.0"
+      },
+      "dependencies": {
+        "@babel/core": {
+          "version": "7.8.3",
+          "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.8.3.tgz",
+          "integrity": "sha512-4XFkf8AwyrEG7Ziu3L2L0Cv+WyY47Tcsp70JFmpftbAA1K7YL/sgE9jh9HyNj08Y/U50ItUchpN0w6HxAoX1rA==",
+          "requires": {
+            "@babel/code-frame": "^7.8.3",
+            "@babel/generator": "^7.8.3",
+            "@babel/helpers": "^7.8.3",
+            "@babel/parser": "^7.8.3",
+            "@babel/template": "^7.8.3",
+            "@babel/traverse": "^7.8.3",
+            "@babel/types": "^7.8.3",
+            "convert-source-map": "^1.7.0",
+            "debug": "^4.1.0",
+            "gensync": "^1.0.0-beta.1",
+            "json5": "^2.1.0",
+            "lodash": "^4.17.13",
+            "resolve": "^1.3.2",
+            "semver": "^5.4.1",
+            "source-map": "^0.5.0"
+          }
+        }
+      }
+    },
+    "@angular/material": {
+      "version": "10.2.7",
+      "resolved": "https://registry.npmjs.org/@angular/material/-/material-10.2.7.tgz",
+      "integrity": "sha512-uk6JkRrKHaM9VFMzX7pWC83YNLVgXPB3D8U1yjSOafCdWwrRZgUHGr8MPlSILCr3o2nxgg5SsKdWcWwHuXXUZA==",
+      "requires": {
+        "tslib": "^2.0.0"
+      }
+    },
+    "@angular/material-moment-adapter": {
+      "version": "10.2.7",
+      "resolved": "https://registry.npmjs.org/@angular/material-moment-adapter/-/material-moment-adapter-10.2.7.tgz",
+      "integrity": "sha512-VaigAiBCz10AvpzgZvdR4SCGnMRxXKx8ukUdeowuoqAFONEPpRdCJmwZ+8bpi9Q/jXlrZJicCMhklj4bBQw6tg==",
+      "requires": {
+        "tslib": "^2.0.0"
+      }
+    },
+    "@angular/platform-browser": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-11.2.14.tgz",
+      "integrity": "sha512-fb7b7ss/gRoP8wLAN17W62leMgjynuyjEPU2eUoAAazsG9f2cgM+z3rK29GYncDVyYQxZUZYnjSqvL6GSXx86A==",
+      "requires": {
+        "tslib": "^2.0.0"
+      }
+    },
+    "@angular/platform-browser-dynamic": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-11.2.14.tgz",
+      "integrity": "sha512-TWTPdFs6iBBcp+/YMsgCRQwdHpWGq8KjeJDJ2tfatGgBD3Gqt2YaHOMST1zPW6RkrmupytTejuVqXzeaKWFxuw==",
+      "requires": {
+        "tslib": "^2.0.0"
+      }
+    },
+    "@angular/platform-server": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-11.2.14.tgz",
+      "integrity": "sha512-VSJ4FSyMPVCE3EGfD4hIK1fZu+KFYi04uL4Co8vchzBQFpXPFABpCS/lGd7rOyvLnKRmUvl4NGS72gQdS00IUw==",
+      "requires": {
+        "domino": "^2.1.2",
+        "tslib": "^2.0.0",
+        "xhr2": "^0.2.0"
+      }
+    },
+    "@angular/router": {
+      "version": "11.2.14",
+      "resolved": "https://registry.npmjs.org/@angular/router/-/router-11.2.14.tgz",
+      "integrity": "sha512-3aYBmj+zrEL9yf/ntIQxHIYaWShZOBKP3U07X2mX+TPMpGlvHDnR7L6bWhQVZwewzMMz7YVR16ldg50IFuAlfA==",
+      "requires": {
+        "tslib": "^2.0.0"
+      }
+    },
+    "@assemblyscript/loader": {
+      "version": "0.10.1",
+      "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz",
+      "integrity": "sha512-H71nDOOL8Y7kWRLqf6Sums+01Q5msqBW2KhDUTemh1tvY04eSkSXrK0uj/4mmY0Xr16/3zyZmsrxN7CKuRbNRg==",
+      "dev": true
+    },
+    "@babel/code-frame": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
+      "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
+      "requires": {
+        "@babel/highlight": "^7.18.6"
+      }
+    },
+    "@babel/compat-data": {
+      "version": "7.20.14",
+      "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.20.14.tgz",
+      "integrity": "sha512-0YpKHD6ImkWMEINCyDAD0HLLUH/lPCefG8ld9it8DJB2wnApraKuhgYTvTY1z7UFIfBTGy5LwncZ+5HWWGbhFw=="
+    },
+    "@babel/core": {
+      "version": "7.20.12",
+      "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.20.12.tgz",
+      "integrity": "sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==",
+      "requires": {
+        "@ampproject/remapping": "^2.1.0",
+        "@babel/code-frame": "^7.18.6",
+        "@babel/generator": "^7.20.7",
+        "@babel/helper-compilation-targets": "^7.20.7",
+        "@babel/helper-module-transforms": "^7.20.11",
+        "@babel/helpers": "^7.20.7",
+        "@babel/parser": "^7.20.7",
+        "@babel/template": "^7.20.7",
+        "@babel/traverse": "^7.20.12",
+        "@babel/types": "^7.20.7",
+        "convert-source-map": "^1.7.0",
+        "debug": "^4.1.0",
+        "gensync": "^1.0.0-beta.2",
+        "json5": "^2.2.2",
+        "semver": "^6.3.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+        }
       }
     },
     "@babel/generator": {
-      "version": "7.12.5",
-      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz",
-      "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==",
+      "version": "7.20.14",
+      "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.20.14.tgz",
+      "integrity": "sha512-AEmuXHdcD3A52HHXxaTmYlb8q/xMEhoRP67B3T4Oq7lbmSoqroMZzjnGj3+i1io3pdnF8iBYVu4Ilj+c4hBxYg==",
       "requires": {
-        "@babel/types": "^7.12.5",
-        "jsesc": "^2.5.1",
-        "source-map": "^0.5.0"
+        "@babel/types": "^7.20.7",
+        "@jridgewell/gen-mapping": "^0.3.2",
+        "jsesc": "^2.5.1"
+      },
+      "dependencies": {
+        "@jridgewell/gen-mapping": {
+          "version": "0.3.2",
+          "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
+          "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
+          "requires": {
+            "@jridgewell/set-array": "^1.0.1",
+            "@jridgewell/sourcemap-codec": "^1.4.10",
+            "@jridgewell/trace-mapping": "^0.3.9"
+          }
+        }
       }
     },
     "@babel/helper-annotate-as-pure": {
-      "version": "7.10.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz",
-      "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz",
+      "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.10.4"
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helper-builder-binary-assignment-operator-visitor": {
-      "version": "7.10.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz",
-      "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==",
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz",
+      "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==",
       "dev": true,
       "requires": {
-        "@babel/helper-explode-assignable-expression": "^7.10.4",
-        "@babel/types": "^7.10.4"
+        "@babel/helper-explode-assignable-expression": "^7.18.6",
+        "@babel/types": "^7.18.9"
       }
     },
     "@babel/helper-compilation-targets": {
-      "version": "7.12.5",
-      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.5.tgz",
-      "integrity": "sha512-+qH6NrscMolUlzOYngSBMIOQpKUGPPsc61Bu5W10mg84LxZ7cmvnBHzARKbDoFxVvqqAbj6Tg6N7bSrWSPXMyw==",
-      "dev": true,
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.7.tgz",
+      "integrity": "sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==",
       "requires": {
-        "@babel/compat-data": "^7.12.5",
-        "@babel/helper-validator-option": "^7.12.1",
-        "browserslist": "^4.14.5",
-        "semver": "^5.5.0"
+        "@babel/compat-data": "^7.20.5",
+        "@babel/helper-validator-option": "^7.18.6",
+        "browserslist": "^4.21.3",
+        "lru-cache": "^5.1.1",
+        "semver": "^6.3.0"
+      },
+      "dependencies": {
+        "lru-cache": {
+          "version": "5.1.1",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
+          "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
+          "requires": {
+            "yallist": "^3.0.2"
+          }
+        },
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+        },
+        "yallist": {
+          "version": "3.1.1",
+          "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
+          "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
+        }
       }
     },
     "@babel/helper-create-class-features-plugin": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz",
-      "integrity": "sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w==",
+      "version": "7.20.12",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.20.12.tgz",
+      "integrity": "sha512-9OunRkbT0JQcednL0UFvbfXpAsUXiGjUk0a7sN8fUXX7Mue79cUSMjHGDRRi/Vz9vYlpIhLV5fMD5dKoMhhsNQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-function-name": "^7.10.4",
-        "@babel/helper-member-expression-to-functions": "^7.12.1",
-        "@babel/helper-optimise-call-expression": "^7.10.4",
-        "@babel/helper-replace-supers": "^7.12.1",
-        "@babel/helper-split-export-declaration": "^7.10.4"
+        "@babel/helper-annotate-as-pure": "^7.18.6",
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-function-name": "^7.19.0",
+        "@babel/helper-member-expression-to-functions": "^7.20.7",
+        "@babel/helper-optimise-call-expression": "^7.18.6",
+        "@babel/helper-replace-supers": "^7.20.7",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0",
+        "@babel/helper-split-export-declaration": "^7.18.6"
       }
     },
     "@babel/helper-create-regexp-features-plugin": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.1.tgz",
-      "integrity": "sha512-rsZ4LGvFTZnzdNZR5HZdmJVuXK8834R5QkF3WvcnBhrlVtF0HSIUC6zbreL9MgjTywhKokn8RIYRiq99+DLAxA==",
+      "version": "7.20.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.20.5.tgz",
+      "integrity": "sha512-m68B1lkg3XDGX5yCvGO0kPx3v9WIYLnzjKfPcQiwntEQa5ZeRkPmo2X/ISJc8qxWGfwUr+kvZAeEzAwLec2r2w==",
       "dev": true,
       "requires": {
-        "@babel/helper-annotate-as-pure": "^7.10.4",
-        "@babel/helper-regex": "^7.10.4",
-        "regexpu-core": "^4.7.1"
+        "@babel/helper-annotate-as-pure": "^7.18.6",
+        "regexpu-core": "^5.2.1"
       }
     },
-    "@babel/helper-define-map": {
-      "version": "7.10.5",
-      "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz",
-      "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==",
+    "@babel/helper-define-polyfill-provider": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.3.tgz",
+      "integrity": "sha512-z5aQKU4IzbqCC1XH0nAqfsFLMVSo22SBKUc0BxGrLkolTdPTructy0ToNnlO2zA4j9Q/7pjMZf0DSY+DSTYzww==",
       "dev": true,
       "requires": {
-        "@babel/helper-function-name": "^7.10.4",
-        "@babel/types": "^7.10.5",
-        "lodash": "^4.17.19"
+        "@babel/helper-compilation-targets": "^7.17.7",
+        "@babel/helper-plugin-utils": "^7.16.7",
+        "debug": "^4.1.1",
+        "lodash.debounce": "^4.0.8",
+        "resolve": "^1.14.2",
+        "semver": "^6.1.2"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "dev": true
+        }
       }
     },
+    "@babel/helper-environment-visitor": {
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
+      "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg=="
+    },
     "@babel/helper-explode-assignable-expression": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.12.1.tgz",
-      "integrity": "sha512-dmUwH8XmlrUpVqgtZ737tK88v07l840z9j3OEhCLwKTkjlvKpfqXVIZ0wpK3aeOxspwGrf/5AP5qLx4rO3w5rA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.18.6.tgz",
+      "integrity": "sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.12.1"
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helper-function-name": {
-      "version": "7.10.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz",
-      "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==",
+      "version": "7.19.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
+      "integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
       "requires": {
-        "@babel/helper-get-function-arity": "^7.10.4",
-        "@babel/template": "^7.10.4",
-        "@babel/types": "^7.10.4"
-      }
-    },
-    "@babel/helper-get-function-arity": {
-      "version": "7.10.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz",
-      "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==",
-      "requires": {
-        "@babel/types": "^7.10.4"
+        "@babel/template": "^7.18.10",
+        "@babel/types": "^7.19.0"
       }
     },
     "@babel/helper-hoist-variables": {
-      "version": "7.10.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz",
-      "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==",
-      "dev": true,
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
+      "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
       "requires": {
-        "@babel/types": "^7.10.4"
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helper-member-expression-to-functions": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.1.tgz",
-      "integrity": "sha512-k0CIe3tXUKTRSoEx1LQEPFU9vRQfqHtl+kf8eNnDqb4AUJEy5pz6aIiog+YWtVm2jpggjS1laH68bPsR+KWWPQ==",
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.20.7.tgz",
+      "integrity": "sha512-9J0CxJLq315fEdi4s7xK5TQaNYjZw+nDVpVqr1axNGKzdrdwYBD5b4uKv3n75aABG0rCCTK8Im8Ww7eYfMrZgw==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.12.1"
+        "@babel/types": "^7.20.7"
       }
     },
     "@babel/helper-module-imports": {
-      "version": "7.12.5",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz",
-      "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==",
-      "dev": true,
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz",
+      "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==",
       "requires": {
-        "@babel/types": "^7.12.5"
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helper-module-transforms": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz",
-      "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==",
-      "dev": true,
+      "version": "7.20.11",
+      "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.20.11.tgz",
+      "integrity": "sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==",
       "requires": {
-        "@babel/helper-module-imports": "^7.12.1",
-        "@babel/helper-replace-supers": "^7.12.1",
-        "@babel/helper-simple-access": "^7.12.1",
-        "@babel/helper-split-export-declaration": "^7.11.0",
-        "@babel/helper-validator-identifier": "^7.10.4",
-        "@babel/template": "^7.10.4",
-        "@babel/traverse": "^7.12.1",
-        "@babel/types": "^7.12.1",
-        "lodash": "^4.17.19"
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-module-imports": "^7.18.6",
+        "@babel/helper-simple-access": "^7.20.2",
+        "@babel/helper-split-export-declaration": "^7.18.6",
+        "@babel/helper-validator-identifier": "^7.19.1",
+        "@babel/template": "^7.20.7",
+        "@babel/traverse": "^7.20.10",
+        "@babel/types": "^7.20.7"
       }
     },
     "@babel/helper-optimise-call-expression": {
-      "version": "7.10.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz",
-      "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz",
+      "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.10.4"
+        "@babel/types": "^7.18.6"
       }
     },
     "@babel/helper-plugin-utils": {
-      "version": "7.10.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz",
-      "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==",
+      "version": "7.20.2",
+      "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz",
+      "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==",
       "dev": true
     },
-    "@babel/helper-regex": {
-      "version": "7.10.5",
-      "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.5.tgz",
-      "integrity": "sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg==",
-      "dev": true,
-      "requires": {
-        "lodash": "^4.17.19"
-      }
-    },
     "@babel/helper-remap-async-to-generator": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.12.1.tgz",
-      "integrity": "sha512-9d0KQCRM8clMPcDwo8SevNs+/9a8yWVVmaE80FGJcEP8N1qToREmWEGnBn8BUlJhYRFz6fqxeRL1sl5Ogsed7A==",
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz",
+      "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==",
       "dev": true,
       "requires": {
-        "@babel/helper-annotate-as-pure": "^7.10.4",
-        "@babel/helper-wrap-function": "^7.10.4",
-        "@babel/types": "^7.12.1"
+        "@babel/helper-annotate-as-pure": "^7.18.6",
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-wrap-function": "^7.18.9",
+        "@babel/types": "^7.18.9"
       }
     },
     "@babel/helper-replace-supers": {
-      "version": "7.12.5",
-      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz",
-      "integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==",
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.20.7.tgz",
+      "integrity": "sha512-vujDMtB6LVfNW13jhlCrp48QNslK6JXi7lQG736HVbHz/mbf4Dc7tIRh1Xf5C0rF7BP8iiSxGMCmY6Ci1ven3A==",
       "dev": true,
       "requires": {
-        "@babel/helper-member-expression-to-functions": "^7.12.1",
-        "@babel/helper-optimise-call-expression": "^7.10.4",
-        "@babel/traverse": "^7.12.5",
-        "@babel/types": "^7.12.5"
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-member-expression-to-functions": "^7.20.7",
+        "@babel/helper-optimise-call-expression": "^7.18.6",
+        "@babel/template": "^7.20.7",
+        "@babel/traverse": "^7.20.7",
+        "@babel/types": "^7.20.7"
       }
     },
     "@babel/helper-simple-access": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz",
-      "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==",
-      "dev": true,
+      "version": "7.20.2",
+      "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz",
+      "integrity": "sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==",
       "requires": {
-        "@babel/types": "^7.12.1"
+        "@babel/types": "^7.20.2"
       }
     },
     "@babel/helper-skip-transparent-expression-wrappers": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz",
-      "integrity": "sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==",
+      "version": "7.20.0",
+      "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz",
+      "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==",
       "dev": true,
       "requires": {
-        "@babel/types": "^7.12.1"
+        "@babel/types": "^7.20.0"
       }
     },
     "@babel/helper-split-export-declaration": {
-      "version": "7.11.0",
-      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz",
-      "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
+      "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
       "requires": {
-        "@babel/types": "^7.11.0"
+        "@babel/types": "^7.18.6"
       }
     },
+    "@babel/helper-string-parser": {
+      "version": "7.19.4",
+      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
+      "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw=="
+    },
     "@babel/helper-validator-identifier": {
-      "version": "7.10.4",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz",
-      "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw=="
+      "version": "7.19.1",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
+      "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w=="
     },
     "@babel/helper-validator-option": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.1.tgz",
-      "integrity": "sha512-YpJabsXlJVWP0USHjnC/AQDTLlZERbON577YUVO/wLpqyj6HAtVYnWaQaN0iUN+1/tWn3c+uKKXjRut5115Y2A==",
-      "dev": true
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz",
+      "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw=="
     },
     "@babel/helper-wrap-function": {
-      "version": "7.12.3",
-      "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.12.3.tgz",
-      "integrity": "sha512-Cvb8IuJDln3rs6tzjW3Y8UeelAOdnpB8xtQ4sme2MSZ9wOxrbThporC0y/EtE16VAtoyEfLM404Xr1e0OOp+ow==",
+      "version": "7.20.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.20.5.tgz",
+      "integrity": "sha512-bYMxIWK5mh+TgXGVqAtnu5Yn1un+v8DDZtqyzKRLUzrh70Eal2O3aZ7aPYiMADO4uKlkzOiRiZ6GX5q3qxvW9Q==",
       "dev": true,
       "requires": {
-        "@babel/helper-function-name": "^7.10.4",
-        "@babel/template": "^7.10.4",
-        "@babel/traverse": "^7.10.4",
-        "@babel/types": "^7.10.4"
+        "@babel/helper-function-name": "^7.19.0",
+        "@babel/template": "^7.18.10",
+        "@babel/traverse": "^7.20.5",
+        "@babel/types": "^7.20.5"
       }
     },
     "@babel/helpers": {
-      "version": "7.12.5",
-      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz",
-      "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==",
+      "version": "7.20.13",
+      "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.20.13.tgz",
+      "integrity": "sha512-nzJ0DWCL3gB5RCXbUO3KIMMsBY2Eqbx8mBpKGE/02PgyRQFcPQLbkQ1vyy596mZLaP+dAfD+R4ckASzNVmW3jg==",
       "requires": {
-        "@babel/template": "^7.10.4",
-        "@babel/traverse": "^7.12.5",
-        "@babel/types": "^7.12.5"
+        "@babel/template": "^7.20.7",
+        "@babel/traverse": "^7.20.13",
+        "@babel/types": "^7.20.7"
       }
     },
     "@babel/highlight": {
-      "version": "7.10.4",
-      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz",
-      "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
+      "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
       "requires": {
-        "@babel/helper-validator-identifier": "^7.10.4",
+        "@babel/helper-validator-identifier": "^7.18.6",
         "chalk": "^2.0.0",
         "js-tokens": "^4.0.0"
       }
     },
     "@babel/parser": {
-      "version": "7.12.5",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.5.tgz",
-      "integrity": "sha512-FVM6RZQ0mn2KCf1VUED7KepYeUWoVShczewOCfm3nzoBybaih51h+sYVVGthW9M6lPByEPTQf+xm27PBdlpwmQ=="
+      "version": "7.20.15",
+      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.15.tgz",
+      "integrity": "sha512-DI4a1oZuf8wC+oAJA9RW6ga3Zbe8RZFt7kD9i4qAspz3I/yHet1VvC3DiSy/fsUvv5pvJuNPh0LPOdCcqinDPg=="
     },
-    "@babel/plugin-proposal-async-generator-functions": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.1.tgz",
-      "integrity": "sha512-d+/o30tJxFxrA1lhzJqiUcEJdI6jKlNregCv5bASeGf2Q4MXmnwH7viDo7nhx1/ohf09oaH8j1GVYG/e3Yqk6A==",
+    "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.18.6.tgz",
+      "integrity": "sha512-Dgxsyg54Fx1d4Nge8UnvTrED63vrwOdPmyvPzlNN/boaliRP54pm3pGzZD1SJUwrBA+Cs/xdG8kXX6Mn/RfISQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4",
-        "@babel/helper-remap-async-to-generator": "^7.12.1",
-        "@babel/plugin-syntax-async-generators": "^7.8.0"
+        "@babel/helper-plugin-utils": "^7.18.6"
+      }
+    },
+    "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.20.7.tgz",
+      "integrity": "sha512-sbr9+wNE5aXMBBFBICk01tt7sBf2Oc9ikRFEcem/ZORup9IMUdNhW7/wVLEbbtlWOsEubJet46mHAL2C8+2jKQ==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0",
+        "@babel/plugin-proposal-optional-chaining": "^7.20.7"
+      }
+    },
+    "@babel/plugin-proposal-async-generator-functions": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz",
+      "integrity": "sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/helper-remap-async-to-generator": "^7.18.9",
+        "@babel/plugin-syntax-async-generators": "^7.8.4"
       }
     },
     "@babel/plugin-proposal-class-properties": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.1.tgz",
-      "integrity": "sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz",
+      "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-create-class-features-plugin": "^7.12.1",
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-create-class-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
+      }
+    },
+    "@babel/plugin-proposal-class-static-block": {
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.20.7.tgz",
+      "integrity": "sha512-AveGOoi9DAjUYYuUAG//Ig69GlazLnoyzMw68VCDux+c1tsnnH/OkYcpz/5xzMkEFC6UxjR5Gw1c+iY2wOGVeQ==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-create-class-features-plugin": "^7.20.7",
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/plugin-syntax-class-static-block": "^7.14.5"
       }
     },
     "@babel/plugin-proposal-dynamic-import": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.1.tgz",
-      "integrity": "sha512-a4rhUSZFuq5W8/OO8H7BL5zspjnc1FLd9hlOxIK/f7qG4a0qsqk8uvF/ywgBA8/OmjsapjpvaEOYItfGG1qIvQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.18.6.tgz",
+      "integrity": "sha512-1auuwmK+Rz13SJj36R+jqFPMJWyKEDd7lLSdOj4oJK0UTgGueSAtkrCvz9ewmgyU/P941Rv2fQwZJN8s6QruXw==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4",
-        "@babel/plugin-syntax-dynamic-import": "^7.8.0"
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/plugin-syntax-dynamic-import": "^7.8.3"
       }
     },
     "@babel/plugin-proposal-export-namespace-from": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.1.tgz",
-      "integrity": "sha512-6CThGf0irEkzujYS5LQcjBx8j/4aQGiVv7J9+2f7pGfxqyKh3WnmVJYW3hdrQjyksErMGBPQrCnHfOtna+WLbw==",
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz",
+      "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/helper-plugin-utils": "^7.18.9",
         "@babel/plugin-syntax-export-namespace-from": "^7.8.3"
       }
     },
     "@babel/plugin-proposal-json-strings": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.12.1.tgz",
-      "integrity": "sha512-GoLDUi6U9ZLzlSda2Df++VSqDJg3CG+dR0+iWsv6XRw1rEq+zwt4DirM9yrxW6XWaTpmai1cWJLMfM8qQJf+yw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.18.6.tgz",
+      "integrity": "sha512-lr1peyn9kOdbYc0xr0OdHTZ5FMqS6Di+H0Fz2I/JwMzGmzJETNeOFq2pBySw6X/KFL5EWDjlJuMsUGRFb8fQgQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4",
-        "@babel/plugin-syntax-json-strings": "^7.8.0"
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/plugin-syntax-json-strings": "^7.8.3"
       }
     },
     "@babel/plugin-proposal-logical-assignment-operators": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.12.1.tgz",
-      "integrity": "sha512-k8ZmVv0JU+4gcUGeCDZOGd0lCIamU/sMtIiX3UWnUc5yzgq6YUGyEolNYD+MLYKfSzgECPcqetVcJP9Afe/aCA==",
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.20.7.tgz",
+      "integrity": "sha512-y7C7cZgpMIjWlKE5T7eJwp+tnRYM89HmRvWM5EQuB5BoHEONjmQ8lSNmBUwOyy/GFRsohJED51YBF79hE1djug==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/helper-plugin-utils": "^7.20.2",
         "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4"
       }
     },
     "@babel/plugin-proposal-nullish-coalescing-operator": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz",
-      "integrity": "sha512-nZY0ESiaQDI1y96+jk6VxMOaL4LPo/QDHBqL+SF3/vl6dHkTwHlOI8L4ZwuRBHgakRBw5zsVylel7QPbbGuYgg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.18.6.tgz",
+      "integrity": "sha512-wQxQzxYeJqHcfppzBDnm1yAY0jSRkUXR2z8RePZYrKwMKgMlE8+Z6LUno+bd6LvbGh8Gltvy74+9pIYkr+XkKA==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4",
-        "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0"
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3"
       }
     },
     "@babel/plugin-proposal-numeric-separator": {
-      "version": "7.12.5",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.5.tgz",
-      "integrity": "sha512-UiAnkKuOrCyjZ3sYNHlRlfuZJbBHknMQ9VMwVeX97Ofwx7RpD6gS2HfqTCh8KNUQgcOm8IKt103oR4KIjh7Q8g==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.18.6.tgz",
+      "integrity": "sha512-ozlZFogPqoLm8WBr5Z8UckIoE4YQ5KESVcNudyXOR8uqIkliTEgJ3RoketfG6pmzLdeZF0H/wjE9/cCEitBl7Q==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4",
+        "@babel/helper-plugin-utils": "^7.18.6",
         "@babel/plugin-syntax-numeric-separator": "^7.10.4"
       }
     },
     "@babel/plugin-proposal-object-rest-spread": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz",
-      "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==",
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz",
+      "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4",
-        "@babel/plugin-syntax-object-rest-spread": "^7.8.0",
-        "@babel/plugin-transform-parameters": "^7.12.1"
+        "@babel/compat-data": "^7.20.5",
+        "@babel/helper-compilation-targets": "^7.20.7",
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
+        "@babel/plugin-transform-parameters": "^7.20.7"
       }
     },
     "@babel/plugin-proposal-optional-catch-binding": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.12.1.tgz",
-      "integrity": "sha512-hFvIjgprh9mMw5v42sJWLI1lzU5L2sznP805zeT6rySVRA0Y18StRhDqhSxlap0oVgItRsB6WSROp4YnJTJz0g==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.18.6.tgz",
+      "integrity": "sha512-Q40HEhs9DJQyaZfUjjn6vE8Cv4GmMHCYuMGIWUnlxH6400VGxOuwWsPt4FxXxJkC/5eOzgn0z21M9gMT4MOhbw==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4",
-        "@babel/plugin-syntax-optional-catch-binding": "^7.8.0"
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/plugin-syntax-optional-catch-binding": "^7.8.3"
       }
     },
     "@babel/plugin-proposal-optional-chaining": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.1.tgz",
-      "integrity": "sha512-c2uRpY6WzaVDzynVY9liyykS+kVU+WRZPMPYpkelXH8KBt1oXoI89kPbZKKG/jDT5UK92FTW2fZkZaJhdiBabw==",
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.20.7.tgz",
+      "integrity": "sha512-T+A7b1kfjtRM51ssoOfS1+wbyCVqorfyZhT99TvxxLMirPShD8CzKMRepMlCBGM5RpHMbn8s+5MMHnPstJH6mQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4",
-        "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1",
-        "@babel/plugin-syntax-optional-chaining": "^7.8.0"
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0",
+        "@babel/plugin-syntax-optional-chaining": "^7.8.3"
       }
     },
     "@babel/plugin-proposal-private-methods": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.12.1.tgz",
-      "integrity": "sha512-mwZ1phvH7/NHK6Kf8LP7MYDogGV+DKB1mryFOEwx5EBNQrosvIczzZFTUmWaeujd5xT6G1ELYWUz3CutMhjE1w==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz",
+      "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==",
       "dev": true,
       "requires": {
-        "@babel/helper-create-class-features-plugin": "^7.12.1",
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-create-class-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
+      }
+    },
+    "@babel/plugin-proposal-private-property-in-object": {
+      "version": "7.20.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.20.5.tgz",
+      "integrity": "sha512-Vq7b9dUA12ByzB4EjQTPo25sFhY+08pQDBSZRtUAkj7lb7jahaHR5igera16QZ+3my1nYR4dKsNdYj5IjPHilQ==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-annotate-as-pure": "^7.18.6",
+        "@babel/helper-create-class-features-plugin": "^7.20.5",
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/plugin-syntax-private-property-in-object": "^7.14.5"
       }
     },
     "@babel/plugin-proposal-unicode-property-regex": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.1.tgz",
-      "integrity": "sha512-MYq+l+PvHuw/rKUz1at/vb6nCnQ2gmJBNaM62z0OgH7B2W1D9pvkpYtlti9bGtizNIU1K3zm4bZF9F91efVY0w==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.18.6.tgz",
+      "integrity": "sha512-2BShG/d5yoZyXZfVePH91urL5wTG6ASZU9M4o03lKK8u8UW1y08OMttBSOADTcJrnPMpvDXRG3G8fyLh4ovs8w==",
       "dev": true,
       "requires": {
-        "@babel/helper-create-regexp-features-plugin": "^7.12.1",
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-create-regexp-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-syntax-async-generators": {
@@ -1049,12 +12926,21 @@
       }
     },
     "@babel/plugin-syntax-class-properties": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz",
-      "integrity": "sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA==",
+      "version": "7.12.13",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz",
+      "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.12.13"
+      }
+    },
+    "@babel/plugin-syntax-class-static-block": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz",
+      "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.14.5"
       }
     },
     "@babel/plugin-syntax-dynamic-import": {
@@ -1075,6 +12961,15 @@
         "@babel/helper-plugin-utils": "^7.8.3"
       }
     },
+    "@babel/plugin-syntax-import-assertions": {
+      "version": "7.20.0",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.20.0.tgz",
+      "integrity": "sha512-IUh1vakzNoWalR8ch/areW7qFopR2AEw03JlG7BbrDqmQ4X3q9uuipQwSGrUn7oGiemKjtSLDhNtQHzMHr1JdQ==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.19.0"
+      }
+    },
     "@babel/plugin-syntax-json-strings": {
       "version": "7.8.3",
       "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz",
@@ -1138,421 +13033,456 @@
         "@babel/helper-plugin-utils": "^7.8.0"
       }
     },
-    "@babel/plugin-syntax-top-level-await": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz",
-      "integrity": "sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A==",
+    "@babel/plugin-syntax-private-property-in-object": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz",
+      "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.14.5"
+      }
+    },
+    "@babel/plugin-syntax-top-level-await": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz",
+      "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-plugin-utils": "^7.14.5"
       }
     },
     "@babel/plugin-transform-arrow-functions": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.12.1.tgz",
-      "integrity": "sha512-5QB50qyN44fzzz4/qxDPQMBCTHgxg3n0xRBLJUmBlLoU/sFvxVWGZF/ZUfMVDQuJUKXaBhbupxIzIfZ6Fwk/0A==",
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.20.7.tgz",
+      "integrity": "sha512-3poA5E7dzDomxj9WXWwuD6A5F3kc7VXwIJO+E+J8qtDtS+pXPAhrgEyh+9GBwBgPq1Z+bB+/JD60lp5jsN7JPQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.20.2"
       }
     },
     "@babel/plugin-transform-async-to-generator": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz",
-      "integrity": "sha512-SDtqoEcarK1DFlRJ1hHRY5HvJUj5kX4qmtpMAm2QnhOlyuMC4TMdCRgW6WXpv93rZeYNeLP22y8Aq2dbcDRM1A==",
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.20.7.tgz",
+      "integrity": "sha512-Uo5gwHPT9vgnSXQxqGtpdufUiWp96gk7yiP4Mp5bm1QMkEmLXBO7PAGYbKoJ6DhAwiNkcHFBol/x5zZZkL/t0Q==",
       "dev": true,
       "requires": {
-        "@babel/helper-module-imports": "^7.12.1",
-        "@babel/helper-plugin-utils": "^7.10.4",
-        "@babel/helper-remap-async-to-generator": "^7.12.1"
+        "@babel/helper-module-imports": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/helper-remap-async-to-generator": "^7.18.9"
       }
     },
     "@babel/plugin-transform-block-scoped-functions": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.1.tgz",
-      "integrity": "sha512-5OpxfuYnSgPalRpo8EWGPzIYf0lHBWORCkj5M0oLBwHdlux9Ri36QqGW3/LR13RSVOAoUUMzoPI/jpE4ABcHoA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.18.6.tgz",
+      "integrity": "sha512-ExUcOqpPWnliRcPqves5HJcJOvHvIIWfuS4sroBUenPuMdmW+SMHDakmtS7qOo13sVppmUijqeTv7qqGsvURpQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-block-scoping": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.1.tgz",
-      "integrity": "sha512-zJyAC9sZdE60r1nVQHblcfCj29Dh2Y0DOvlMkcqSo0ckqjiCwNiUezUKw+RjOCwGfpLRwnAeQ2XlLpsnGkvv9w==",
+      "version": "7.20.15",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.20.15.tgz",
+      "integrity": "sha512-Vv4DMZ6MiNOhu/LdaZsT/bsLRxgL94d269Mv4R/9sp6+Mp++X/JqypZYypJXLlM4mlL352/Egzbzr98iABH1CA==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.20.2"
       }
     },
     "@babel/plugin-transform-classes": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.12.1.tgz",
-      "integrity": "sha512-/74xkA7bVdzQTBeSUhLLJgYIcxw/dpEpCdRDiHgPJ3Mv6uC11UhjpOhl72CgqbBCmt1qtssCyB2xnJm1+PFjog==",
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.20.7.tgz",
+      "integrity": "sha512-LWYbsiXTPKl+oBlXUGlwNlJZetXD5Am+CyBdqhPsDVjM9Jc8jwBJFrKhHf900Kfk2eZG1y9MAG3UNajol7A4VQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-annotate-as-pure": "^7.10.4",
-        "@babel/helper-define-map": "^7.10.4",
-        "@babel/helper-function-name": "^7.10.4",
-        "@babel/helper-optimise-call-expression": "^7.10.4",
-        "@babel/helper-plugin-utils": "^7.10.4",
-        "@babel/helper-replace-supers": "^7.12.1",
-        "@babel/helper-split-export-declaration": "^7.10.4",
+        "@babel/helper-annotate-as-pure": "^7.18.6",
+        "@babel/helper-compilation-targets": "^7.20.7",
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-function-name": "^7.19.0",
+        "@babel/helper-optimise-call-expression": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/helper-replace-supers": "^7.20.7",
+        "@babel/helper-split-export-declaration": "^7.18.6",
         "globals": "^11.1.0"
       }
     },
     "@babel/plugin-transform-computed-properties": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.12.1.tgz",
-      "integrity": "sha512-vVUOYpPWB7BkgUWPo4C44mUQHpTZXakEqFjbv8rQMg7TC6S6ZhGZ3otQcRH6u7+adSlE5i0sp63eMC/XGffrzg==",
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.20.7.tgz",
+      "integrity": "sha512-Lz7MvBK6DTjElHAmfu6bfANzKcxpyNPeYBGEafyA6E5HtRpjpZwU+u7Qrgz/2OR0z+5TvKYbPdphfSaAcZBrYQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/template": "^7.20.7"
       }
     },
     "@babel/plugin-transform-destructuring": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.12.1.tgz",
-      "integrity": "sha512-fRMYFKuzi/rSiYb2uRLiUENJOKq4Gnl+6qOv5f8z0TZXg3llUwUhsNNwrwaT/6dUhJTzNpBr+CUvEWBtfNY1cw==",
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz",
+      "integrity": "sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.20.2"
       }
     },
     "@babel/plugin-transform-dotall-regex": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.1.tgz",
-      "integrity": "sha512-B2pXeRKoLszfEW7J4Hg9LoFaWEbr/kzo3teWHmtFCszjRNa/b40f9mfeqZsIDLLt/FjwQ6pz/Gdlwy85xNckBA==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.18.6.tgz",
+      "integrity": "sha512-6S3jpun1eEbAxq7TdjLotAsl4WpQI9DxfkycRcKrjhQYzU87qpXdknpBg/e+TdcMehqGnLFi7tnFUBR02Vq6wg==",
       "dev": true,
       "requires": {
-        "@babel/helper-create-regexp-features-plugin": "^7.12.1",
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-create-regexp-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-duplicate-keys": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.1.tgz",
-      "integrity": "sha512-iRght0T0HztAb/CazveUpUQrZY+aGKKaWXMJ4uf9YJtqxSUe09j3wteztCUDRHs+SRAL7yMuFqUsLoAKKzgXjw==",
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz",
+      "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.18.9"
       }
     },
     "@babel/plugin-transform-exponentiation-operator": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.1.tgz",
-      "integrity": "sha512-7tqwy2bv48q+c1EHbXK0Zx3KXd2RVQp6OC7PbwFNt/dPTAV3Lu5sWtWuAj8owr5wqtWnqHfl2/mJlUmqkChKug==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.18.6.tgz",
+      "integrity": "sha512-wzEtc0+2c88FVR34aQmiz56dxEkxr2g8DQb/KfaFa1JYXOFVsbhvAonFN6PwVWj++fKmku8NP80plJ5Et4wqHw==",
       "dev": true,
       "requires": {
-        "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4",
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-builder-binary-assignment-operator-visitor": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-for-of": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.12.1.tgz",
-      "integrity": "sha512-Zaeq10naAsuHo7heQvyV0ptj4dlZJwZgNAtBYBnu5nNKJoW62m0zKcIEyVECrUKErkUkg6ajMy4ZfnVZciSBhg==",
+      "version": "7.18.8",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz",
+      "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-function-name": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.1.tgz",
-      "integrity": "sha512-JF3UgJUILoFrFMEnOJLJkRHSk6LUSXLmEFsA23aR2O5CSLUxbeUX1IZ1YQ7Sn0aXb601Ncwjx73a+FVqgcljVw==",
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz",
+      "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-function-name": "^7.10.4",
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-compilation-targets": "^7.18.9",
+        "@babel/helper-function-name": "^7.18.9",
+        "@babel/helper-plugin-utils": "^7.18.9"
       }
     },
     "@babel/plugin-transform-literals": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.1.tgz",
-      "integrity": "sha512-+PxVGA+2Ag6uGgL0A5f+9rklOnnMccwEBzwYFL3EUaKuiyVnUipyXncFcfjSkbimLrODoqki1U9XxZzTvfN7IQ==",
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz",
+      "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.18.9"
       }
     },
     "@babel/plugin-transform-member-expression-literals": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.1.tgz",
-      "integrity": "sha512-1sxePl6z9ad0gFMB9KqmYofk34flq62aqMt9NqliS/7hPEpURUCMbyHXrMPlo282iY7nAvUB1aQd5mg79UD9Jg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.18.6.tgz",
+      "integrity": "sha512-qSF1ihLGO3q+/g48k85tUjD033C29TNTVB2paCwZPVmOsjn9pClvYYrM2VeJpBY2bcNkuny0YUyTNRyRxJ54KA==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-modules-amd": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.12.1.tgz",
-      "integrity": "sha512-tDW8hMkzad5oDtzsB70HIQQRBiTKrhfgwC/KkJeGsaNFTdWhKNt/BiE8c5yj19XiGyrxpbkOfH87qkNg1YGlOQ==",
+      "version": "7.20.11",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.20.11.tgz",
+      "integrity": "sha512-NuzCt5IIYOW0O30UvqktzHYR2ud5bOWbY0yaxWZ6G+aFzOMJvrs5YHNikrbdaT15+KNO31nPOy5Fim3ku6Zb5g==",
       "dev": true,
       "requires": {
-        "@babel/helper-module-transforms": "^7.12.1",
-        "@babel/helper-plugin-utils": "^7.10.4",
-        "babel-plugin-dynamic-import-node": "^2.3.3"
+        "@babel/helper-module-transforms": "^7.20.11",
+        "@babel/helper-plugin-utils": "^7.20.2"
       }
     },
     "@babel/plugin-transform-modules-commonjs": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.12.1.tgz",
-      "integrity": "sha512-dY789wq6l0uLY8py9c1B48V8mVL5gZh/+PQ5ZPrylPYsnAvnEMjqsUXkuoDVPeVK+0VyGar+D08107LzDQ6pag==",
+      "version": "7.20.11",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.20.11.tgz",
+      "integrity": "sha512-S8e1f7WQ7cimJQ51JkAaDrEtohVEitXjgCGAS2N8S31Y42E+kWwfSz83LYz57QdBm7q9diARVqanIaH2oVgQnw==",
       "dev": true,
       "requires": {
-        "@babel/helper-module-transforms": "^7.12.1",
-        "@babel/helper-plugin-utils": "^7.10.4",
-        "@babel/helper-simple-access": "^7.12.1",
-        "babel-plugin-dynamic-import-node": "^2.3.3"
+        "@babel/helper-module-transforms": "^7.20.11",
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/helper-simple-access": "^7.20.2"
       }
     },
     "@babel/plugin-transform-modules-systemjs": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.12.1.tgz",
-      "integrity": "sha512-Hn7cVvOavVh8yvW6fLwveFqSnd7rbQN3zJvoPNyNaQSvgfKmDBO9U1YL9+PCXGRlZD9tNdWTy5ACKqMuzyn32Q==",
+      "version": "7.20.11",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.20.11.tgz",
+      "integrity": "sha512-vVu5g9BPQKSFEmvt2TA4Da5N+QVS66EX21d8uoOihC+OCpUoGvzVsXeqFdtAEfVa5BILAeFt+U7yVmLbQnAJmw==",
       "dev": true,
       "requires": {
-        "@babel/helper-hoist-variables": "^7.10.4",
-        "@babel/helper-module-transforms": "^7.12.1",
-        "@babel/helper-plugin-utils": "^7.10.4",
-        "@babel/helper-validator-identifier": "^7.10.4",
-        "babel-plugin-dynamic-import-node": "^2.3.3"
+        "@babel/helper-hoist-variables": "^7.18.6",
+        "@babel/helper-module-transforms": "^7.20.11",
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/helper-validator-identifier": "^7.19.1"
       }
     },
     "@babel/plugin-transform-modules-umd": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.12.1.tgz",
-      "integrity": "sha512-aEIubCS0KHKM0zUos5fIoQm+AZUMt1ZvMpqz0/H5qAQ7vWylr9+PLYurT+Ic7ID/bKLd4q8hDovaG3Zch2uz5Q==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.18.6.tgz",
+      "integrity": "sha512-dcegErExVeXcRqNtkRU/z8WlBLnvD4MRnHgNs3MytRO1Mn1sHRyhbcpYbVMGclAqOjdW+9cfkdZno9dFdfKLfQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-module-transforms": "^7.12.1",
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-module-transforms": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-named-capturing-groups-regex": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.1.tgz",
-      "integrity": "sha512-tB43uQ62RHcoDp9v2Nsf+dSM8sbNodbEicbQNA53zHz8pWUhsgHSJCGpt7daXxRydjb0KnfmB+ChXOv3oADp1Q==",
+      "version": "7.20.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.20.5.tgz",
+      "integrity": "sha512-mOW4tTzi5iTLnw+78iEq3gr8Aoq4WNRGpmSlrogqaiCBoR1HFhpU4JkpQFOHfeYx3ReVIFWOQJS4aZBRvuZ6mA==",
       "dev": true,
       "requires": {
-        "@babel/helper-create-regexp-features-plugin": "^7.12.1"
+        "@babel/helper-create-regexp-features-plugin": "^7.20.5",
+        "@babel/helper-plugin-utils": "^7.20.2"
       }
     },
     "@babel/plugin-transform-new-target": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.1.tgz",
-      "integrity": "sha512-+eW/VLcUL5L9IvJH7rT1sT0CzkdUTvPrXC2PXTn/7z7tXLBuKvezYbGdxD5WMRoyvyaujOq2fWoKl869heKjhw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.6.tgz",
+      "integrity": "sha512-DjwFA/9Iu3Z+vrAn+8pBUGcjhxKguSMlsFqeCKbhb9BAV756v0krzVK04CRDi/4aqmk8BsHb4a/gFcaA5joXRw==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-object-super": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.1.tgz",
-      "integrity": "sha512-AvypiGJH9hsquNUn+RXVcBdeE3KHPZexWRdimhuV59cSoOt5kFBmqlByorAeUlGG2CJWd0U+4ZtNKga/TB0cAw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.18.6.tgz",
+      "integrity": "sha512-uvGz6zk+pZoS1aTZrOvrbj6Pp/kK2mp45t2B+bTDre2UgsZZ8EZLSJtUg7m/no0zOJUWgFONpB7Zv9W2tSaFlA==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4",
-        "@babel/helper-replace-supers": "^7.12.1"
+        "@babel/helper-plugin-utils": "^7.18.6",
+        "@babel/helper-replace-supers": "^7.18.6"
       }
     },
     "@babel/plugin-transform-parameters": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.12.1.tgz",
-      "integrity": "sha512-xq9C5EQhdPK23ZeCdMxl8bbRnAgHFrw5EOC3KJUsSylZqdkCaFEXxGSBuTSObOpiiHHNyb82es8M1QYgfQGfNg==",
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz",
+      "integrity": "sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.20.2"
       }
     },
     "@babel/plugin-transform-property-literals": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.1.tgz",
-      "integrity": "sha512-6MTCR/mZ1MQS+AwZLplX4cEySjCpnIF26ToWo942nqn8hXSm7McaHQNeGx/pt7suI1TWOWMfa/NgBhiqSnX0cQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.18.6.tgz",
+      "integrity": "sha512-cYcs6qlgafTud3PAzrrRNbQtfpQ8+y/+M5tKmksS9+M1ckbH6kzY8MrexEM9mcA6JDsukE19iIRvAyYl463sMg==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-regenerator": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.1.tgz",
-      "integrity": "sha512-gYrHqs5itw6i4PflFX3OdBPMQdPbF4bj2REIUxlMRUFk0/ZOAIpDFuViuxPjUL7YC8UPnf+XG7/utJvqXdPKng==",
+      "version": "7.20.5",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.20.5.tgz",
+      "integrity": "sha512-kW/oO7HPBtntbsahzQ0qSE3tFvkFwnbozz3NWFhLGqH75vLEg+sCGngLlhVkePlCs3Jv0dBBHDzCHxNiFAQKCQ==",
       "dev": true,
       "requires": {
-        "regenerator-transform": "^0.14.2"
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "regenerator-transform": "^0.15.1"
       }
     },
     "@babel/plugin-transform-reserved-words": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.1.tgz",
-      "integrity": "sha512-pOnUfhyPKvZpVyBHhSBoX8vfA09b7r00Pmm1sH+29ae2hMTKVmSp4Ztsr8KBKjLjx17H0eJqaRC3bR2iThM54A==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.18.6.tgz",
+      "integrity": "sha512-oX/4MyMoypzHjFrT1CdivfKZ+XvIPMFXwwxHp/r0Ddy2Vuomt4HDFGmft1TAY2yiTKiNSsh3kjBAzcM8kSdsjA==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-runtime": {
-      "version": "7.11.0",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.11.0.tgz",
-      "integrity": "sha512-LFEsP+t3wkYBlis8w6/kmnd6Kb1dxTd+wGJ8MlxTGzQo//ehtqlVL4S9DNUa53+dtPSQobN2CXx4d81FqC58cw==",
+      "version": "7.19.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.19.6.tgz",
+      "integrity": "sha512-PRH37lz4JU156lYFW1p8OxE5i7d6Sl/zV58ooyr+q1J1lnQPyg5tIiXlIwNVhJaY4W3TmOtdc8jqdXQcB1v5Yw==",
       "dev": true,
       "requires": {
-        "@babel/helper-module-imports": "^7.10.4",
-        "@babel/helper-plugin-utils": "^7.10.4",
-        "resolve": "^1.8.1",
-        "semver": "^5.5.1"
+        "@babel/helper-module-imports": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.19.0",
+        "babel-plugin-polyfill-corejs2": "^0.3.3",
+        "babel-plugin-polyfill-corejs3": "^0.6.0",
+        "babel-plugin-polyfill-regenerator": "^0.4.1",
+        "semver": "^6.3.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "dev": true
+        }
       }
     },
     "@babel/plugin-transform-shorthand-properties": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.1.tgz",
-      "integrity": "sha512-GFZS3c/MhX1OusqB1MZ1ct2xRzX5ppQh2JU1h2Pnfk88HtFTM+TWQqJNfwkmxtPQtb/s1tk87oENfXJlx7rSDw==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.18.6.tgz",
+      "integrity": "sha512-eCLXXJqv8okzg86ywZJbRn19YJHU4XUa55oz2wbHhaQVn/MM+XhukiT7SYqp/7o00dg52Rj51Ny+Ecw4oyoygw==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-spread": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.12.1.tgz",
-      "integrity": "sha512-vuLp8CP0BE18zVYjsEBZ5xoCecMK6LBMMxYzJnh01rxQRvhNhH1csMMmBfNo5tGpGO+NhdSNW2mzIvBu3K1fng==",
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.20.7.tgz",
+      "integrity": "sha512-ewBbHQ+1U/VnH1fxltbJqDeWBU1oNLG8Dj11uIv3xVf7nrQu0bPGe5Rf716r7K5Qz+SqtAOVswoVunoiBtGhxw==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4",
-        "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1"
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0"
       }
     },
     "@babel/plugin-transform-sticky-regex": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.1.tgz",
-      "integrity": "sha512-CiUgKQ3AGVk7kveIaPEET1jNDhZZEl1RPMWdTBE1799bdz++SwqDHStmxfCtDfBhQgCl38YRiSnrMuUMZIWSUQ==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.18.6.tgz",
+      "integrity": "sha512-kfiDrDQ+PBsQDO85yj1icueWMfGfJFKN1KCkndygtu/C9+XUfydLC8Iv5UYJqRwy4zk8EcplRxEOeLyjq1gm6Q==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4",
-        "@babel/helper-regex": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/plugin-transform-template-literals": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.12.1.tgz",
-      "integrity": "sha512-b4Zx3KHi+taXB1dVRBhVJtEPi9h1THCeKmae2qP0YdUHIFhVjtpqqNfxeVAa1xeHVhAy4SbHxEwx5cltAu5apw==",
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz",
+      "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.18.9"
       }
     },
     "@babel/plugin-transform-typeof-symbol": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.1.tgz",
-      "integrity": "sha512-EPGgpGy+O5Kg5pJFNDKuxt9RdmTgj5sgrus2XVeMp/ZIbOESadgILUbm50SNpghOh3/6yrbsH+NB5+WJTmsA7Q==",
+      "version": "7.18.9",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz",
+      "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.18.9"
       }
     },
     "@babel/plugin-transform-unicode-escapes": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.1.tgz",
-      "integrity": "sha512-I8gNHJLIc7GdApm7wkVnStWssPNbSRMPtgHdmH3sRM1zopz09UWPS4x5V4n1yz/MIWTVnJ9sp6IkuXdWM4w+2Q==",
+      "version": "7.18.10",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz",
+      "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==",
       "dev": true,
       "requires": {
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-plugin-utils": "^7.18.9"
       }
     },
     "@babel/plugin-transform-unicode-regex": {
-      "version": "7.12.1",
-      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.1.tgz",
-      "integrity": "sha512-SqH4ClNngh/zGwHZOOQMTD+e8FGWexILV+ePMyiDJttAWRh5dhDL8rcl5lSgU3Huiq6Zn6pWTMvdPAb21Dwdyg==",
+      "version": "7.18.6",
+      "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.18.6.tgz",
+      "integrity": "sha512-gE7A6Lt7YLnNOL3Pb9BNeZvi+d8l7tcRrG4+pwJjK9hD2xX4mEvjlQW60G9EEmfXVYRPv9VRQcyegIVHCql/AA==",
       "dev": true,
       "requires": {
-        "@babel/helper-create-regexp-features-plugin": "^7.12.1",
-        "@babel/helper-plugin-utils": "^7.10.4"
+        "@babel/helper-create-regexp-features-plugin": "^7.18.6",
+        "@babel/helper-plugin-utils": "^7.18.6"
       }
     },
     "@babel/preset-env": {
-      "version": "7.11.0",
-      "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.11.0.tgz",
-      "integrity": "sha512-2u1/k7rG/gTh02dylX2kL3S0IJNF+J6bfDSp4DI2Ma8QN6Y9x9pmAax59fsCk6QUQG0yqH47yJWA+u1I1LccAg==",
+      "version": "7.20.2",
+      "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.20.2.tgz",
+      "integrity": "sha512-1G0efQEWR1EHkKvKHqbG+IN/QdgwfByUpM5V5QroDzGV2t3S/WXNQd693cHiHTlCFMpr9B6FkPFXDA2lQcKoDg==",
       "dev": true,
       "requires": {
-        "@babel/compat-data": "^7.11.0",
-        "@babel/helper-compilation-targets": "^7.10.4",
-        "@babel/helper-module-imports": "^7.10.4",
-        "@babel/helper-plugin-utils": "^7.10.4",
-        "@babel/plugin-proposal-async-generator-functions": "^7.10.4",
-        "@babel/plugin-proposal-class-properties": "^7.10.4",
-        "@babel/plugin-proposal-dynamic-import": "^7.10.4",
-        "@babel/plugin-proposal-export-namespace-from": "^7.10.4",
-        "@babel/plugin-proposal-json-strings": "^7.10.4",
-        "@babel/plugin-proposal-logical-assignment-operators": "^7.11.0",
-        "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4",
-        "@babel/plugin-proposal-numeric-separator": "^7.10.4",
-        "@babel/plugin-proposal-object-rest-spread": "^7.11.0",
-        "@babel/plugin-proposal-optional-catch-binding": "^7.10.4",
-        "@babel/plugin-proposal-optional-chaining": "^7.11.0",
-        "@babel/plugin-proposal-private-methods": "^7.10.4",
-        "@babel/plugin-proposal-unicode-property-regex": "^7.10.4",
-        "@babel/plugin-syntax-async-generators": "^7.8.0",
-        "@babel/plugin-syntax-class-properties": "^7.10.4",
-        "@babel/plugin-syntax-dynamic-import": "^7.8.0",
+        "@babel/compat-data": "^7.20.1",
+        "@babel/helper-compilation-targets": "^7.20.0",
+        "@babel/helper-plugin-utils": "^7.20.2",
+        "@babel/helper-validator-option": "^7.18.6",
+        "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6",
+        "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9",
+        "@babel/plugin-proposal-async-generator-functions": "^7.20.1",
+        "@babel/plugin-proposal-class-properties": "^7.18.6",
+        "@babel/plugin-proposal-class-static-block": "^7.18.6",
+        "@babel/plugin-proposal-dynamic-import": "^7.18.6",
+        "@babel/plugin-proposal-export-namespace-from": "^7.18.9",
+        "@babel/plugin-proposal-json-strings": "^7.18.6",
+        "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9",
+        "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6",
+        "@babel/plugin-proposal-numeric-separator": "^7.18.6",
+        "@babel/plugin-proposal-object-rest-spread": "^7.20.2",
+        "@babel/plugin-proposal-optional-catch-binding": "^7.18.6",
+        "@babel/plugin-proposal-optional-chaining": "^7.18.9",
+        "@babel/plugin-proposal-private-methods": "^7.18.6",
+        "@babel/plugin-proposal-private-property-in-object": "^7.18.6",
+        "@babel/plugin-proposal-unicode-property-regex": "^7.18.6",
+        "@babel/plugin-syntax-async-generators": "^7.8.4",
+        "@babel/plugin-syntax-class-properties": "^7.12.13",
+        "@babel/plugin-syntax-class-static-block": "^7.14.5",
+        "@babel/plugin-syntax-dynamic-import": "^7.8.3",
         "@babel/plugin-syntax-export-namespace-from": "^7.8.3",
-        "@babel/plugin-syntax-json-strings": "^7.8.0",
+        "@babel/plugin-syntax-import-assertions": "^7.20.0",
+        "@babel/plugin-syntax-json-strings": "^7.8.3",
         "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4",
-        "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0",
+        "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3",
         "@babel/plugin-syntax-numeric-separator": "^7.10.4",
-        "@babel/plugin-syntax-object-rest-spread": "^7.8.0",
-        "@babel/plugin-syntax-optional-catch-binding": "^7.8.0",
-        "@babel/plugin-syntax-optional-chaining": "^7.8.0",
-        "@babel/plugin-syntax-top-level-await": "^7.10.4",
-        "@babel/plugin-transform-arrow-functions": "^7.10.4",
-        "@babel/plugin-transform-async-to-generator": "^7.10.4",
-        "@babel/plugin-transform-block-scoped-functions": "^7.10.4",
-        "@babel/plugin-transform-block-scoping": "^7.10.4",
-        "@babel/plugin-transform-classes": "^7.10.4",
-        "@babel/plugin-transform-computed-properties": "^7.10.4",
-        "@babel/plugin-transform-destructuring": "^7.10.4",
-        "@babel/plugin-transform-dotall-regex": "^7.10.4",
-        "@babel/plugin-transform-duplicate-keys": "^7.10.4",
-        "@babel/plugin-transform-exponentiation-operator": "^7.10.4",
-        "@babel/plugin-transform-for-of": "^7.10.4",
-        "@babel/plugin-transform-function-name": "^7.10.4",
-        "@babel/plugin-transform-literals": "^7.10.4",
-        "@babel/plugin-transform-member-expression-literals": "^7.10.4",
-        "@babel/plugin-transform-modules-amd": "^7.10.4",
-        "@babel/plugin-transform-modules-commonjs": "^7.10.4",
-        "@babel/plugin-transform-modules-systemjs": "^7.10.4",
-        "@babel/plugin-transform-modules-umd": "^7.10.4",
-        "@babel/plugin-transform-named-capturing-groups-regex": "^7.10.4",
-        "@babel/plugin-transform-new-target": "^7.10.4",
-        "@babel/plugin-transform-object-super": "^7.10.4",
-        "@babel/plugin-transform-parameters": "^7.10.4",
-        "@babel/plugin-transform-property-literals": "^7.10.4",
-        "@babel/plugin-transform-regenerator": "^7.10.4",
-        "@babel/plugin-transform-reserved-words": "^7.10.4",
-        "@babel/plugin-transform-shorthand-properties": "^7.10.4",
-        "@babel/plugin-transform-spread": "^7.11.0",
-        "@babel/plugin-transform-sticky-regex": "^7.10.4",
-        "@babel/plugin-transform-template-literals": "^7.10.4",
-        "@babel/plugin-transform-typeof-symbol": "^7.10.4",
-        "@babel/plugin-transform-unicode-escapes": "^7.10.4",
-        "@babel/plugin-transform-unicode-regex": "^7.10.4",
-        "@babel/preset-modules": "^0.1.3",
-        "@babel/types": "^7.11.0",
-        "browserslist": "^4.12.0",
-        "core-js-compat": "^3.6.2",
-        "invariant": "^2.2.2",
-        "levenary": "^1.1.1",
-        "semver": "^5.5.0"
+        "@babel/plugin-syntax-object-rest-spread": "^7.8.3",
+        "@babel/plugin-syntax-optional-catch-binding": "^7.8.3",
+        "@babel/plugin-syntax-optional-chaining": "^7.8.3",
+        "@babel/plugin-syntax-private-property-in-object": "^7.14.5",
+        "@babel/plugin-syntax-top-level-await": "^7.14.5",
+        "@babel/plugin-transform-arrow-functions": "^7.18.6",
+        "@babel/plugin-transform-async-to-generator": "^7.18.6",
+        "@babel/plugin-transform-block-scoped-functions": "^7.18.6",
+        "@babel/plugin-transform-block-scoping": "^7.20.2",
+        "@babel/plugin-transform-classes": "^7.20.2",
+        "@babel/plugin-transform-computed-properties": "^7.18.9",
+        "@babel/plugin-transform-destructuring": "^7.20.2",
+        "@babel/plugin-transform-dotall-regex": "^7.18.6",
+        "@babel/plugin-transform-duplicate-keys": "^7.18.9",
+        "@babel/plugin-transform-exponentiation-operator": "^7.18.6",
+        "@babel/plugin-transform-for-of": "^7.18.8",
+        "@babel/plugin-transform-function-name": "^7.18.9",
+        "@babel/plugin-transform-literals": "^7.18.9",
+        "@babel/plugin-transform-member-expression-literals": "^7.18.6",
+        "@babel/plugin-transform-modules-amd": "^7.19.6",
+        "@babel/plugin-transform-modules-commonjs": "^7.19.6",
+        "@babel/plugin-transform-modules-systemjs": "^7.19.6",
+        "@babel/plugin-transform-modules-umd": "^7.18.6",
+        "@babel/plugin-transform-named-capturing-groups-regex": "^7.19.1",
+        "@babel/plugin-transform-new-target": "^7.18.6",
+        "@babel/plugin-transform-object-super": "^7.18.6",
+        "@babel/plugin-transform-parameters": "^7.20.1",
+        "@babel/plugin-transform-property-literals": "^7.18.6",
+        "@babel/plugin-transform-regenerator": "^7.18.6",
+        "@babel/plugin-transform-reserved-words": "^7.18.6",
+        "@babel/plugin-transform-shorthand-properties": "^7.18.6",
+        "@babel/plugin-transform-spread": "^7.19.0",
+        "@babel/plugin-transform-sticky-regex": "^7.18.6",
+        "@babel/plugin-transform-template-literals": "^7.18.9",
+        "@babel/plugin-transform-typeof-symbol": "^7.18.9",
+        "@babel/plugin-transform-unicode-escapes": "^7.18.10",
+        "@babel/plugin-transform-unicode-regex": "^7.18.6",
+        "@babel/preset-modules": "^0.1.5",
+        "@babel/types": "^7.20.2",
+        "babel-plugin-polyfill-corejs2": "^0.3.3",
+        "babel-plugin-polyfill-corejs3": "^0.6.0",
+        "babel-plugin-polyfill-regenerator": "^0.4.1",
+        "core-js-compat": "^3.25.1",
+        "semver": "^6.3.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "dev": true
+        }
       }
     },
     "@babel/preset-modules": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz",
-      "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==",
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz",
+      "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==",
       "dev": true,
       "requires": {
         "@babel/helper-plugin-utils": "^7.0.0",
@@ -1562,114 +13492,456 @@
         "esutils": "^2.0.2"
       }
     },
+    "@babel/regjsgen": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz",
+      "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==",
+      "dev": true
+    },
     "@babel/runtime": {
-      "version": "7.11.2",
-      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz",
-      "integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==",
+      "version": "7.20.13",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz",
+      "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==",
       "dev": true,
       "requires": {
-        "regenerator-runtime": "^0.13.4"
+        "regenerator-runtime": "^0.13.11"
       }
     },
     "@babel/template": {
-      "version": "7.10.4",
-      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz",
-      "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==",
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
+      "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
       "requires": {
-        "@babel/code-frame": "^7.10.4",
-        "@babel/parser": "^7.10.4",
-        "@babel/types": "^7.10.4"
+        "@babel/code-frame": "^7.18.6",
+        "@babel/parser": "^7.20.7",
+        "@babel/types": "^7.20.7"
       }
     },
     "@babel/traverse": {
-      "version": "7.12.5",
-      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.5.tgz",
-      "integrity": "sha512-xa15FbQnias7z9a62LwYAA5SZZPkHIXpd42C6uW68o8uTuua96FHZy1y61Va5P/i83FAAcMpW8+A/QayntzuqA==",
+      "version": "7.20.13",
+      "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.20.13.tgz",
+      "integrity": "sha512-kMJXfF0T6DIS9E8cgdLCSAL+cuCK+YEZHWiLK0SXpTo8YRj5lpJu3CDNKiIBCne4m9hhTIqUg6SYTAI39tAiVQ==",
       "requires": {
-        "@babel/code-frame": "^7.10.4",
-        "@babel/generator": "^7.12.5",
-        "@babel/helper-function-name": "^7.10.4",
-        "@babel/helper-split-export-declaration": "^7.11.0",
-        "@babel/parser": "^7.12.5",
-        "@babel/types": "^7.12.5",
+        "@babel/code-frame": "^7.18.6",
+        "@babel/generator": "^7.20.7",
+        "@babel/helper-environment-visitor": "^7.18.9",
+        "@babel/helper-function-name": "^7.19.0",
+        "@babel/helper-hoist-variables": "^7.18.6",
+        "@babel/helper-split-export-declaration": "^7.18.6",
+        "@babel/parser": "^7.20.13",
+        "@babel/types": "^7.20.7",
         "debug": "^4.1.0",
-        "globals": "^11.1.0",
-        "lodash": "^4.17.19"
+        "globals": "^11.1.0"
       }
     },
     "@babel/types": {
-      "version": "7.12.6",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.6.tgz",
-      "integrity": "sha512-hwyjw6GvjBLiyy3W0YQf0Z5Zf4NpYejUnKFcfcUhZCSffoBBp30w6wP2Wn6pk31jMYZvcOrB/1b7cGXvEoKogA==",
+      "version": "7.20.7",
+      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.20.7.tgz",
+      "integrity": "sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==",
       "requires": {
-        "@babel/helper-validator-identifier": "^7.10.4",
-        "lodash": "^4.17.19",
+        "@babel/helper-string-parser": "^7.19.4",
+        "@babel/helper-validator-identifier": "^7.19.1",
         "to-fast-properties": "^2.0.0"
       }
     },
-    "@istanbuljs/schema": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz",
-      "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==",
+    "@discoveryjs/json-ext": {
+      "version": "0.5.7",
+      "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz",
+      "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
       "dev": true
     },
-    "@jsdevtools/coverage-istanbul-loader": {
-      "version": "3.0.5",
-      "resolved": "https://registry.npmjs.org/@jsdevtools/coverage-istanbul-loader/-/coverage-istanbul-loader-3.0.5.tgz",
-      "integrity": "sha512-EUCPEkaRPvmHjWAAZkWMT7JDzpw7FKB00WTISaiXsbNOd5hCHg77XLA8sLYLFDo1zepYLo2w7GstN8YBqRXZfA==",
+    "@esbuild/android-arm": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.8.tgz",
+      "integrity": "sha512-0/rb91GYKhrtbeglJXOhAv9RuYimgI8h623TplY2X+vA4EXnk3Zj1fXZreJ0J3OJJu1bwmb0W7g+2cT/d8/l/w==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/android-arm64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.8.tgz",
+      "integrity": "sha512-oa/N5j6v1svZQs7EIRPqR8f+Bf8g6HBDjD/xHC02radE/NjKHK7oQmtmLxPs1iVwYyvE+Kolo6lbpfEQ9xnhxQ==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/android-x64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.8.tgz",
+      "integrity": "sha512-bTliMLqD7pTOoPg4zZkXqCDuzIUguEWLpeqkNfC41ODBHwoUgZ2w5JBeYimv4oP6TDVocoYmEhZrCLQTrH89bg==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/darwin-arm64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.8.tgz",
+      "integrity": "sha512-ghAbV3ia2zybEefXRRm7+lx8J/rnupZT0gp9CaGy/3iolEXkJ6LYRq4IpQVI9zR97ID80KJVoUlo3LSeA/sMAg==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/darwin-x64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.8.tgz",
+      "integrity": "sha512-n5WOpyvZ9TIdv2V1K3/iIkkJeKmUpKaCTdun9buhGRWfH//osmUjlv4Z5mmWdPWind/VGcVxTHtLfLCOohsOXw==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/freebsd-arm64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.8.tgz",
+      "integrity": "sha512-a/SATTaOhPIPFWvHZDoZYgxaZRVHn0/LX1fHLGfZ6C13JqFUZ3K6SMD6/HCtwOQ8HnsNaEeokdiDSFLuizqv5A==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/freebsd-x64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.8.tgz",
+      "integrity": "sha512-xpFJb08dfXr5+rZc4E+ooZmayBW6R3q59daCpKZ/cDU96/kvDM+vkYzNeTJCGd8rtO6fHWMq5Rcv/1cY6p6/0Q==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/linux-arm": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.8.tgz",
+      "integrity": "sha512-6Ij8gfuGszcEwZpi5jQIJCVIACLS8Tz2chnEBfYjlmMzVsfqBP1iGmHQPp7JSnZg5xxK9tjCc+pJ2WtAmPRFVA==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/linux-arm64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.8.tgz",
+      "integrity": "sha512-v3iwDQuDljLTxpsqQDl3fl/yihjPAyOguxuloON9kFHYwopeJEf1BkDXODzYyXEI19gisEsQlG1bM65YqKSIww==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/linux-ia32": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.8.tgz",
+      "integrity": "sha512-8svILYKhE5XetuFk/B6raFYIyIqydQi+GngEXJgdPdI7OMKUbSd7uzR02wSY4kb53xBrClLkhH4Xs8P61Q2BaA==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/linux-loong64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.8.tgz",
+      "integrity": "sha512-B6FyMeRJeV0NpyEOYlm5qtQfxbdlgmiGdD+QsipzKfFky0K5HW5Td6dyK3L3ypu1eY4kOmo7wW0o94SBqlqBSA==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/linux-mips64el": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.8.tgz",
+      "integrity": "sha512-CCb67RKahNobjm/eeEqeD/oJfJlrWyw29fgiyB6vcgyq97YAf3gCOuP6qMShYSPXgnlZe/i4a8WFHBw6N8bYAA==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/linux-ppc64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.8.tgz",
+      "integrity": "sha512-bytLJOi55y55+mGSdgwZ5qBm0K9WOCh0rx+vavVPx+gqLLhxtSFU0XbeYy/dsAAD6xECGEv4IQeFILaSS2auXw==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/linux-riscv64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.8.tgz",
+      "integrity": "sha512-2YpRyQJmKVBEHSBLa8kBAtbhucaclb6ex4wchfY0Tj3Kg39kpjeJ9vhRU7x4mUpq8ISLXRXH1L0dBYjAeqzZAw==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/linux-s390x": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.8.tgz",
+      "integrity": "sha512-QgbNY/V3IFXvNf11SS6exkpVcX0LJcob+0RWCgV9OiDAmVElnxciHIisoSix9uzYzScPmS6dJFbZULdSAEkQVw==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/linux-x64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.8.tgz",
+      "integrity": "sha512-mM/9S0SbAFDBc4OPoyP6SEOo5324LpUxdpeIUUSrSTOfhHU9hEfqRngmKgqILqwx/0DVJBzeNW7HmLEWp9vcOA==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/netbsd-x64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.8.tgz",
+      "integrity": "sha512-eKUYcWaWTaYr9zbj8GertdVtlt1DTS1gNBWov+iQfWuWyuu59YN6gSEJvFzC5ESJ4kMcKR0uqWThKUn5o8We6Q==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/openbsd-x64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.8.tgz",
+      "integrity": "sha512-Vc9J4dXOboDyMXKD0eCeW0SIeEzr8K9oTHJU+Ci1mZc5njPfhKAqkRt3B/fUNU7dP+mRyralPu8QUkiaQn7iIg==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/sunos-x64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.8.tgz",
+      "integrity": "sha512-0xvOTNuPXI7ft1LYUgiaXtpCEjp90RuBBYovdd2lqAFxje4sEucurg30M1WIm03+3jxByd3mfo+VUmPtRSVuOw==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/win32-arm64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.8.tgz",
+      "integrity": "sha512-G0JQwUI5WdEFEnYNKzklxtBheCPkuDdu1YrtRrjuQv30WsYbkkoixKxLLv8qhJmNI+ATEWquZe/N0d0rpr55Mg==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/win32-ia32": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.8.tgz",
+      "integrity": "sha512-Fqy63515xl20OHGFykjJsMnoIWS+38fqfg88ClvPXyDbLtgXal2DTlhb1TfTX34qWi3u4I7Cq563QcHpqgLx8w==",
+      "dev": true,
+      "optional": true
+    },
+    "@esbuild/win32-x64": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.8.tgz",
+      "integrity": "sha512-1iuezdyDNngPnz8rLRDO2C/ZZ/emJLb72OsZeqQ6gL6Avko/XCXZw+NuxBSNhBAP13Hie418V7VMt9et1FMvpg==",
+      "dev": true,
+      "optional": true
+    },
+    "@istanbuljs/load-nyc-config": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
+      "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==",
       "dev": true,
       "requires": {
-        "convert-source-map": "^1.7.0",
-        "istanbul-lib-instrument": "^4.0.3",
-        "loader-utils": "^2.0.0",
-        "merge-source-map": "^1.1.0",
-        "schema-utils": "^2.7.0"
+        "camelcase": "^5.3.1",
+        "find-up": "^4.1.0",
+        "get-package-type": "^0.1.0",
+        "js-yaml": "^3.13.1",
+        "resolve-from": "^5.0.0"
       }
     },
-    "@ngtools/webpack": {
-      "version": "10.2.0",
-      "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-10.2.0.tgz",
-      "integrity": "sha512-W4SSFNQhIiC8JRhIn3c4mb1+fsFKiHp+THVMAUNo+wRZEt/rgzsCdnqv0EmQJJojZhnilUIyB/wVYJu2+S/Bxg==",
+    "@istanbuljs/schema": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz",
+      "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==",
+      "dev": true
+    },
+    "@jridgewell/gen-mapping": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz",
+      "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==",
+      "requires": {
+        "@jridgewell/set-array": "^1.0.0",
+        "@jridgewell/sourcemap-codec": "^1.4.10"
+      }
+    },
+    "@jridgewell/resolve-uri": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz",
+      "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w=="
+    },
+    "@jridgewell/set-array": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz",
+      "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ=="
+    },
+    "@jridgewell/source-map": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz",
+      "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==",
       "dev": true,
       "requires": {
-        "@angular-devkit/core": "10.2.0",
-        "enhanced-resolve": "4.3.0",
-        "webpack-sources": "1.4.3"
+        "@jridgewell/gen-mapping": "^0.3.0",
+        "@jridgewell/trace-mapping": "^0.3.9"
+      },
+      "dependencies": {
+        "@jridgewell/gen-mapping": {
+          "version": "0.3.2",
+          "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz",
+          "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==",
+          "dev": true,
+          "requires": {
+            "@jridgewell/set-array": "^1.0.1",
+            "@jridgewell/sourcemap-codec": "^1.4.10",
+            "@jridgewell/trace-mapping": "^0.3.9"
+          }
+        }
       }
     },
+    "@jridgewell/sourcemap-codec": {
+      "version": "1.4.14",
+      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
+      "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
+    },
+    "@jridgewell/trace-mapping": {
+      "version": "0.3.17",
+      "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz",
+      "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==",
+      "requires": {
+        "@jridgewell/resolve-uri": "3.1.0",
+        "@jridgewell/sourcemap-codec": "1.4.14"
+      }
+    },
+    "@leichtgewicht/ip-codec": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz",
+      "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
+      "dev": true
+    },
     "@nodelib/fs.scandir": {
-      "version": "2.1.3",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz",
-      "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==",
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
       "dev": true,
       "requires": {
-        "@nodelib/fs.stat": "2.0.3",
+        "@nodelib/fs.stat": "2.0.5",
         "run-parallel": "^1.1.9"
       }
     },
     "@nodelib/fs.stat": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz",
-      "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==",
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
       "dev": true
     },
     "@nodelib/fs.walk": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz",
-      "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==",
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
       "dev": true,
       "requires": {
-        "@nodelib/fs.scandir": "2.1.3",
+        "@nodelib/fs.scandir": "2.1.5",
         "fastq": "^1.6.0"
       }
     },
-    "@npmcli/move-file": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.0.1.tgz",
-      "integrity": "sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw==",
+    "@npmcli/ci-detect": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/@npmcli/ci-detect/-/ci-detect-1.4.0.tgz",
+      "integrity": "sha512-3BGrt6FLjqM6br5AhWRKTr3u5GIVkjRYeAFrMp3HjnfICrg4xOrVRwFavKT6tsp++bq5dluL5t8ME/Nha/6c1Q==",
+      "dev": true
+    },
+    "@npmcli/fs": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz",
+      "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==",
       "dev": true,
       "requires": {
-        "mkdirp": "^1.0.4"
+        "semver": "^7.3.5"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "7.3.8",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+          "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        }
+      }
+    },
+    "@npmcli/git": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-2.1.0.tgz",
+      "integrity": "sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw==",
+      "dev": true,
+      "requires": {
+        "@npmcli/promise-spawn": "^1.3.2",
+        "lru-cache": "^6.0.0",
+        "mkdirp": "^1.0.4",
+        "npm-pick-manifest": "^6.1.1",
+        "promise-inflight": "^1.0.1",
+        "promise-retry": "^2.0.1",
+        "semver": "^7.3.5",
+        "which": "^2.0.2"
+      },
+      "dependencies": {
+        "err-code": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz",
+          "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==",
+          "dev": true
+        },
+        "hosted-git-info": {
+          "version": "4.1.0",
+          "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz",
+          "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        },
+        "mkdirp": {
+          "version": "1.0.4",
+          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+          "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
+          "dev": true
+        },
+        "npm-package-arg": {
+          "version": "8.1.5",
+          "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.5.tgz",
+          "integrity": "sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q==",
+          "dev": true,
+          "requires": {
+            "hosted-git-info": "^4.0.1",
+            "semver": "^7.3.4",
+            "validate-npm-package-name": "^3.0.0"
+          }
+        },
+        "npm-pick-manifest": {
+          "version": "6.1.1",
+          "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz",
+          "integrity": "sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA==",
+          "dev": true,
+          "requires": {
+            "npm-install-checks": "^4.0.0",
+            "npm-normalize-package-bin": "^1.0.1",
+            "npm-package-arg": "^8.1.2",
+            "semver": "^7.3.4"
+          }
+        },
+        "promise-retry": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz",
+          "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==",
+          "dev": true,
+          "requires": {
+            "err-code": "^2.0.2",
+            "retry": "^0.12.0"
+          }
+        },
+        "retry": {
+          "version": "0.12.0",
+          "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
+          "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=",
+          "dev": true
+        },
+        "semver": {
+          "version": "7.3.7",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+          "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        }
+      }
+    },
+    "@npmcli/installed-package-contents": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz",
+      "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==",
+      "dev": true,
+      "requires": {
+        "npm-bundled": "^1.1.1",
+        "npm-normalize-package-bin": "^1.0.1"
+      }
+    },
+    "@npmcli/move-file": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz",
+      "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==",
+      "dev": true,
+      "requires": {
+        "mkdirp": "^1.0.4",
+        "rimraf": "^3.0.2"
       },
       "dependencies": {
         "mkdirp": {
@@ -1680,61 +13952,201 @@
         }
       }
     },
-    "@schematics/angular": {
-      "version": "10.2.0",
-      "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-10.2.0.tgz",
-      "integrity": "sha512-rJRTTTL8CMMFb3ebCvAVHKHxuNzRqy/HtbXhJ82l5Xo/jXcm74eV2Q0RBUrNo1yBKWFIR+FIwiXLJaGcC/R9Pw==",
+    "@npmcli/node-gyp": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.3.tgz",
+      "integrity": "sha512-fnkhw+fmX65kiLqk6E3BFLXNC26rUhK90zVwe2yncPliVT/Qos3xjhTLE59Df8KnPlcwIERXKVlU1bXoUQ+liA==",
+      "dev": true
+    },
+    "@npmcli/promise-spawn": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz",
+      "integrity": "sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg==",
       "dev": true,
       "requires": {
-        "@angular-devkit/core": "10.2.0",
-        "@angular-devkit/schematics": "10.2.0",
-        "jsonc-parser": "2.3.0"
+        "infer-owner": "^1.0.4"
+      }
+    },
+    "@npmcli/run-script": {
+      "version": "1.8.6",
+      "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.6.tgz",
+      "integrity": "sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g==",
+      "dev": true,
+      "requires": {
+        "@npmcli/node-gyp": "^1.0.2",
+        "@npmcli/promise-spawn": "^1.3.2",
+        "node-gyp": "^7.1.0",
+        "read-package-json-fast": "^2.0.1"
+      },
+      "dependencies": {
+        "read-package-json-fast": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz",
+          "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==",
+          "dev": true,
+          "requires": {
+            "json-parse-even-better-errors": "^2.3.0",
+            "npm-normalize-package-bin": "^1.0.1"
+          }
+        }
+      }
+    },
+    "@polka/url": {
+      "version": "1.0.0-next.21",
+      "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.21.tgz",
+      "integrity": "sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==",
+      "dev": true
+    },
+    "@schematics/angular": {
+      "version": "11.2.19",
+      "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-11.2.19.tgz",
+      "integrity": "sha512-cZys7nRo/CI81EtPu4VJiAyv53gPfIfLteykhrTQpAp9AZK9UuRHauiJq7BhHRAUEc3z148xjSQgMvEu7/vAuA==",
+      "dev": true,
+      "requires": {
+        "@angular-devkit/core": "11.2.19",
+        "@angular-devkit/schematics": "11.2.19",
+        "jsonc-parser": "3.0.0"
       }
     },
     "@schematics/update": {
-      "version": "0.1002.0",
-      "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.1002.0.tgz",
-      "integrity": "sha512-g2bfJSAj3x/YL0GNhnHsDSQmO6DoxSnLxoFLqNN5+ukxK5jq7OZNDwMJGxZ3X6RcSMWKEkIKL/wlq9yhj2T/kw==",
+      "version": "0.1102.19",
+      "resolved": "https://registry.npmjs.org/@schematics/update/-/update-0.1102.19.tgz",
+      "integrity": "sha512-NdWzL6n/ZEgnposWdAPo8PTOn+8Baf/J9isjF+QOUUMbpZY/+QfLpej7eDAlcQ2Begiz/selMsnod70r9PYZUg==",
       "dev": true,
       "requires": {
-        "@angular-devkit/core": "10.2.0",
-        "@angular-devkit/schematics": "10.2.0",
+        "@angular-devkit/core": "11.2.19",
+        "@angular-devkit/schematics": "11.2.19",
         "@yarnpkg/lockfile": "1.1.0",
-        "ini": "1.3.5",
+        "ini": "2.0.0",
         "npm-package-arg": "^8.0.0",
-        "pacote": "9.5.12",
-        "semver": "7.3.2",
+        "pacote": "11.2.4",
+        "semver": "7.3.4",
         "semver-intersect": "1.4.0"
       },
       "dependencies": {
         "semver": {
-          "version": "7.3.2",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
-          "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
-          "dev": true
+          "version": "7.3.4",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.4.tgz",
+          "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
         }
       }
     },
-    "@types/glob": {
-      "version": "7.1.3",
-      "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz",
-      "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==",
+    "@tootallnate/once": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
+      "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==",
+      "dev": true
+    },
+    "@types/body-parser": {
+      "version": "1.19.2",
+      "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz",
+      "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==",
       "dev": true,
       "requires": {
-        "@types/minimatch": "*",
+        "@types/connect": "*",
+        "@types/node": "*"
+      }
+    },
+    "@types/bonjour": {
+      "version": "3.5.10",
+      "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz",
+      "integrity": "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*"
+      }
+    },
+    "@types/connect": {
+      "version": "3.4.35",
+      "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz",
+      "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*"
+      }
+    },
+    "@types/connect-history-api-fallback": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz",
+      "integrity": "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==",
+      "dev": true,
+      "requires": {
+        "@types/express-serve-static-core": "*",
+        "@types/node": "*"
+      }
+    },
+    "@types/eslint": {
+      "version": "8.21.0",
+      "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.0.tgz",
+      "integrity": "sha512-35EhHNOXgxnUgh4XCJsGhE7zdlDhYDN/aMG6UbkByCFFNgQ7b3U+uVoqBpicFydR8JEfgdjCF7SJ7MiJfzuiTA==",
+      "dev": true,
+      "requires": {
+        "@types/estree": "*",
+        "@types/json-schema": "*"
+      }
+    },
+    "@types/eslint-scope": {
+      "version": "3.7.4",
+      "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.4.tgz",
+      "integrity": "sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==",
+      "dev": true,
+      "requires": {
+        "@types/eslint": "*",
+        "@types/estree": "*"
+      }
+    },
+    "@types/estree": {
+      "version": "0.0.51",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz",
+      "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==",
+      "dev": true
+    },
+    "@types/express": {
+      "version": "4.17.17",
+      "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz",
+      "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==",
+      "dev": true,
+      "requires": {
+        "@types/body-parser": "*",
+        "@types/express-serve-static-core": "^4.17.33",
+        "@types/qs": "*",
+        "@types/serve-static": "*"
+      }
+    },
+    "@types/express-serve-static-core": {
+      "version": "4.17.33",
+      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz",
+      "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*",
+        "@types/qs": "*",
+        "@types/range-parser": "*"
+      }
+    },
+    "@types/http-proxy": {
+      "version": "1.17.10",
+      "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.10.tgz",
+      "integrity": "sha512-Qs5aULi+zV1bwKAg5z1PWnDXWmsn+LxIvUGv6E2+OOMYhclZMO+OXd9pYVf2gLykf2I7IV2u7oTHwChPNsvJ7g==",
+      "dev": true,
+      "requires": {
         "@types/node": "*"
       }
     },
     "@types/json-schema": {
-      "version": "7.0.6",
-      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz",
-      "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==",
+      "version": "7.0.11",
+      "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz",
+      "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==",
       "dev": true
     },
-    "@types/minimatch": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz",
-      "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==",
+    "@types/mime": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
+      "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==",
       "dev": true
     },
     "@types/moment-timezone": {
@@ -1752,209 +14164,210 @@
       "integrity": "sha512-8Jduo8wvvwDzEVJCOvS/G6sgilOLvvhn1eMmK3TW8/T217O7u1jdrK6ImKLv80tVryaPSVeKu6sjDEiFjd4/eg==",
       "dev": true
     },
-    "@types/q": {
-      "version": "1.5.4",
-      "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.4.tgz",
-      "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==",
+    "@types/parse-json": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
+      "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==",
       "dev": true
     },
-    "@types/source-list-map": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz",
-      "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==",
+    "@types/qs": {
+      "version": "6.9.7",
+      "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
+      "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==",
       "dev": true
     },
-    "@types/webpack-sources": {
-      "version": "0.1.8",
-      "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-0.1.8.tgz",
-      "integrity": "sha512-JHB2/xZlXOjzjBB6fMOpH1eQAfsrpqVVIbneE0Rok16WXwFaznaI5vfg75U5WgGJm7V9W1c4xeRQDjX/zwvghA==",
+    "@types/range-parser": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz",
+      "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
+      "dev": true
+    },
+    "@types/retry": {
+      "version": "0.12.0",
+      "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz",
+      "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==",
+      "dev": true
+    },
+    "@types/serve-index": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz",
+      "integrity": "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==",
       "dev": true,
       "requires": {
-        "@types/node": "*",
-        "@types/source-list-map": "*",
-        "source-map": "^0.6.1"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
+        "@types/express": "*"
+      }
+    },
+    "@types/serve-static": {
+      "version": "1.15.1",
+      "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz",
+      "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==",
+      "dev": true,
+      "requires": {
+        "@types/mime": "*",
+        "@types/node": "*"
+      }
+    },
+    "@types/sockjs": {
+      "version": "0.3.33",
+      "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz",
+      "integrity": "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*"
+      }
+    },
+    "@types/ws": {
+      "version": "8.5.4",
+      "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz",
+      "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*"
       }
     },
     "@webassemblyjs/ast": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz",
-      "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==",
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
+      "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==",
       "dev": true,
       "requires": {
-        "@webassemblyjs/helper-module-context": "1.9.0",
-        "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
-        "@webassemblyjs/wast-parser": "1.9.0"
+        "@webassemblyjs/helper-numbers": "1.11.1",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.1"
       }
     },
     "@webassemblyjs/floating-point-hex-parser": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz",
-      "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==",
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz",
+      "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==",
       "dev": true
     },
     "@webassemblyjs/helper-api-error": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz",
-      "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==",
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz",
+      "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==",
       "dev": true
     },
     "@webassemblyjs/helper-buffer": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz",
-      "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==",
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz",
+      "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==",
       "dev": true
     },
-    "@webassemblyjs/helper-code-frame": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz",
-      "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==",
+    "@webassemblyjs/helper-numbers": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz",
+      "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==",
       "dev": true,
       "requires": {
-        "@webassemblyjs/wast-printer": "1.9.0"
-      }
-    },
-    "@webassemblyjs/helper-fsm": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz",
-      "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==",
-      "dev": true
-    },
-    "@webassemblyjs/helper-module-context": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz",
-      "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==",
-      "dev": true,
-      "requires": {
-        "@webassemblyjs/ast": "1.9.0"
+        "@webassemblyjs/floating-point-hex-parser": "1.11.1",
+        "@webassemblyjs/helper-api-error": "1.11.1",
+        "@xtuc/long": "4.2.2"
       }
     },
     "@webassemblyjs/helper-wasm-bytecode": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz",
-      "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==",
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz",
+      "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==",
       "dev": true
     },
     "@webassemblyjs/helper-wasm-section": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz",
-      "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==",
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz",
+      "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==",
       "dev": true,
       "requires": {
-        "@webassemblyjs/ast": "1.9.0",
-        "@webassemblyjs/helper-buffer": "1.9.0",
-        "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
-        "@webassemblyjs/wasm-gen": "1.9.0"
+        "@webassemblyjs/ast": "1.11.1",
+        "@webassemblyjs/helper-buffer": "1.11.1",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
+        "@webassemblyjs/wasm-gen": "1.11.1"
       }
     },
     "@webassemblyjs/ieee754": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz",
-      "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==",
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz",
+      "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==",
       "dev": true,
       "requires": {
         "@xtuc/ieee754": "^1.2.0"
       }
     },
     "@webassemblyjs/leb128": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz",
-      "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==",
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz",
+      "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==",
       "dev": true,
       "requires": {
         "@xtuc/long": "4.2.2"
       }
     },
     "@webassemblyjs/utf8": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz",
-      "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==",
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz",
+      "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==",
       "dev": true
     },
     "@webassemblyjs/wasm-edit": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz",
-      "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==",
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz",
+      "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==",
       "dev": true,
       "requires": {
-        "@webassemblyjs/ast": "1.9.0",
-        "@webassemblyjs/helper-buffer": "1.9.0",
-        "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
-        "@webassemblyjs/helper-wasm-section": "1.9.0",
-        "@webassemblyjs/wasm-gen": "1.9.0",
-        "@webassemblyjs/wasm-opt": "1.9.0",
-        "@webassemblyjs/wasm-parser": "1.9.0",
-        "@webassemblyjs/wast-printer": "1.9.0"
+        "@webassemblyjs/ast": "1.11.1",
+        "@webassemblyjs/helper-buffer": "1.11.1",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
+        "@webassemblyjs/helper-wasm-section": "1.11.1",
+        "@webassemblyjs/wasm-gen": "1.11.1",
+        "@webassemblyjs/wasm-opt": "1.11.1",
+        "@webassemblyjs/wasm-parser": "1.11.1",
+        "@webassemblyjs/wast-printer": "1.11.1"
       }
     },
     "@webassemblyjs/wasm-gen": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz",
-      "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==",
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz",
+      "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==",
       "dev": true,
       "requires": {
-        "@webassemblyjs/ast": "1.9.0",
-        "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
-        "@webassemblyjs/ieee754": "1.9.0",
-        "@webassemblyjs/leb128": "1.9.0",
-        "@webassemblyjs/utf8": "1.9.0"
+        "@webassemblyjs/ast": "1.11.1",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
+        "@webassemblyjs/ieee754": "1.11.1",
+        "@webassemblyjs/leb128": "1.11.1",
+        "@webassemblyjs/utf8": "1.11.1"
       }
     },
     "@webassemblyjs/wasm-opt": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz",
-      "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==",
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz",
+      "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==",
       "dev": true,
       "requires": {
-        "@webassemblyjs/ast": "1.9.0",
-        "@webassemblyjs/helper-buffer": "1.9.0",
-        "@webassemblyjs/wasm-gen": "1.9.0",
-        "@webassemblyjs/wasm-parser": "1.9.0"
+        "@webassemblyjs/ast": "1.11.1",
+        "@webassemblyjs/helper-buffer": "1.11.1",
+        "@webassemblyjs/wasm-gen": "1.11.1",
+        "@webassemblyjs/wasm-parser": "1.11.1"
       }
     },
     "@webassemblyjs/wasm-parser": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz",
-      "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==",
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz",
+      "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==",
       "dev": true,
       "requires": {
-        "@webassemblyjs/ast": "1.9.0",
-        "@webassemblyjs/helper-api-error": "1.9.0",
-        "@webassemblyjs/helper-wasm-bytecode": "1.9.0",
-        "@webassemblyjs/ieee754": "1.9.0",
-        "@webassemblyjs/leb128": "1.9.0",
-        "@webassemblyjs/utf8": "1.9.0"
-      }
-    },
-    "@webassemblyjs/wast-parser": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz",
-      "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==",
-      "dev": true,
-      "requires": {
-        "@webassemblyjs/ast": "1.9.0",
-        "@webassemblyjs/floating-point-hex-parser": "1.9.0",
-        "@webassemblyjs/helper-api-error": "1.9.0",
-        "@webassemblyjs/helper-code-frame": "1.9.0",
-        "@webassemblyjs/helper-fsm": "1.9.0",
-        "@xtuc/long": "4.2.2"
+        "@webassemblyjs/ast": "1.11.1",
+        "@webassemblyjs/helper-api-error": "1.11.1",
+        "@webassemblyjs/helper-wasm-bytecode": "1.11.1",
+        "@webassemblyjs/ieee754": "1.11.1",
+        "@webassemblyjs/leb128": "1.11.1",
+        "@webassemblyjs/utf8": "1.11.1"
       }
     },
     "@webassemblyjs/wast-printer": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz",
-      "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==",
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz",
+      "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==",
       "dev": true,
       "requires": {
-        "@webassemblyjs/ast": "1.9.0",
-        "@webassemblyjs/wast-parser": "1.9.0",
+        "@webassemblyjs/ast": "1.11.1",
         "@xtuc/long": "4.2.2"
       }
     },
@@ -1976,30 +14389,26 @@
       "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==",
       "dev": true
     },
-    "JSONStream": {
-      "version": "1.3.5",
-      "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz",
-      "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==",
-      "dev": true,
-      "requires": {
-        "jsonparse": "^1.2.0",
-        "through": ">=2.2.7 <3"
-      }
-    },
     "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==",
+      "dev": true
+    },
+    "abbrev": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+      "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
       "dev": true
     },
     "accepts": {
-      "version": "1.3.7",
-      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
-      "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+      "version": "1.3.8",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
+      "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
       "dev": true,
       "requires": {
-        "mime-types": "~2.1.24",
-        "negotiator": "0.6.2"
+        "mime-types": "~2.1.34",
+        "negotiator": "0.6.3"
       }
     },
     "ace-builds": {
@@ -2008,42 +14417,64 @@
       "integrity": "sha512-G+chJctFPiiLGvs3+/Mly3apXTcfgE45dT5yp12BcWZ1kUs+gm0qd3/fv4gsz6fVag4mM0moHVpjHDIgph6Psg=="
     },
     "acorn": {
-      "version": "6.4.2",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz",
-      "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==",
+      "version": "8.8.2",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz",
+      "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==",
       "dev": true
     },
+    "acorn-import-assertions": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz",
+      "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==",
+      "dev": true,
+      "requires": {}
+    },
     "acorn-walk": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
-      "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
+      "version": "8.2.0",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+      "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
       "dev": true
     },
     "adjust-sourcemap-loader": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-3.0.0.tgz",
-      "integrity": "sha512-YBrGyT2/uVQ/c6Rr+t6ZJXniY03YtHGMJQYal368burRGYKqhx9qGTWqcBU5s1CwYY9E/ri63RYyG1IacMZtqw==",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz",
+      "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==",
       "dev": true,
       "requires": {
         "loader-utils": "^2.0.0",
         "regex-parser": "^2.2.11"
+      },
+      "dependencies": {
+        "loader-utils": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
+          "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
+          "dev": true,
+          "requires": {
+            "big.js": "^5.2.2",
+            "emojis-list": "^3.0.0",
+            "json5": "^2.1.2"
+          }
+        }
       }
     },
     "agent-base": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
-      "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+      "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
       "dev": true,
       "requires": {
-        "es6-promisify": "^5.0.0"
+        "debug": "4"
       }
     },
     "agentkeepalive": {
-      "version": "3.5.2",
-      "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz",
-      "integrity": "sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ==",
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz",
+      "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==",
       "dev": true,
       "requires": {
+        "debug": "^4.1.0",
+        "depd": "^1.1.2",
         "humanize-ms": "^1.2.1"
       }
     },
@@ -2058,9 +14489,9 @@
       }
     },
     "ajv": {
-      "version": "6.12.4",
-      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.4.tgz",
-      "integrity": "sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==",
+      "version": "6.12.6",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
+      "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
       "dev": true,
       "requires": {
         "fast-deep-equal": "^3.1.1",
@@ -2069,28 +14500,46 @@
         "uri-js": "^4.2.2"
       }
     },
-    "ajv-errors": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz",
-      "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==",
-      "dev": true
+    "ajv-formats": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
+      "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
+      "dev": true,
+      "requires": {
+        "ajv": "^8.0.0"
+      },
+      "dependencies": {
+        "ajv": {
+          "version": "8.12.0",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+          "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+          "dev": true,
+          "requires": {
+            "fast-deep-equal": "^3.1.1",
+            "json-schema-traverse": "^1.0.0",
+            "require-from-string": "^2.0.2",
+            "uri-js": "^4.2.2"
+          }
+        },
+        "json-schema-traverse": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+          "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+          "dev": true
+        }
+      }
     },
     "ajv-keywords": {
       "version": "3.5.2",
       "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
       "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==",
-      "dev": true
-    },
-    "alphanum-sort": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz",
-      "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=",
-      "dev": true
+      "dev": true,
+      "requires": {}
     },
     "ansi-colors": {
-      "version": "3.2.4",
-      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
-      "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==",
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
+      "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
       "dev": true
     },
     "ansi-escapes": {
@@ -2102,16 +14551,16 @@
         "type-fest": "^0.11.0"
       }
     },
-    "ansi-html": {
-      "version": "0.0.7",
-      "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz",
-      "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=",
+    "ansi-html-community": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz",
+      "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==",
       "dev": true
     },
     "ansi-regex": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
-      "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
     },
     "ansi-styles": {
       "version": "3.2.1",
@@ -2122,10 +14571,9 @@
       }
     },
     "anymatch": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
-      "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
-      "dev": true,
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
       "requires": {
         "normalize-path": "^3.0.0",
         "picomatch": "^2.0.4"
@@ -2143,6 +14591,16 @@
       "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
       "dev": true
     },
+    "are-we-there-yet": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz",
+      "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==",
+      "dev": true,
+      "requires": {
+        "delegates": "^1.0.0",
+        "readable-stream": "^2.0.6"
+      }
+    },
     "arg": {
       "version": "4.1.3",
       "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
@@ -2168,60 +14626,12 @@
         "commander": "^2.11.0"
       }
     },
-    "arity-n": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/arity-n/-/arity-n-1.0.4.tgz",
-      "integrity": "sha1-2edrEXM+CFacCEeuezmyhgswt0U=",
-      "dev": true
-    },
-    "arr-diff": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
-      "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
-      "dev": true
-    },
-    "arr-flatten": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
-      "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
-      "dev": true
-    },
-    "arr-union": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
-      "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
-      "dev": true
-    },
     "array-flatten": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz",
       "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==",
       "dev": true
     },
-    "array-union": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
-      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
-      "dev": true
-    },
-    "array-uniq": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
-      "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=",
-      "dev": true
-    },
-    "array-unique": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
-      "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
-      "dev": true
-    },
-    "asap": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
-      "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=",
-      "dev": true
-    },
     "asn1": {
       "version": "0.2.4",
       "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
@@ -2231,117 +14641,36 @@
         "safer-buffer": "~2.1.0"
       }
     },
-    "asn1.js": {
-      "version": "5.4.1",
-      "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz",
-      "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==",
-      "dev": true,
-      "requires": {
-        "bn.js": "^4.0.0",
-        "inherits": "^2.0.1",
-        "minimalistic-assert": "^1.0.0",
-        "safer-buffer": "^2.1.0"
-      },
-      "dependencies": {
-        "bn.js": {
-          "version": "4.11.9",
-          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
-          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
-          "dev": true
-        }
-      }
-    },
-    "assert": {
-      "version": "1.5.0",
-      "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz",
-      "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==",
-      "dev": true,
-      "requires": {
-        "object-assign": "^4.1.1",
-        "util": "0.10.3"
-      },
-      "dependencies": {
-        "inherits": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
-          "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=",
-          "dev": true
-        },
-        "util": {
-          "version": "0.10.3",
-          "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
-          "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
-          "dev": true,
-          "requires": {
-            "inherits": "2.0.1"
-          }
-        }
-      }
-    },
     "assert-plus": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
       "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
       "dev": true
     },
-    "assign-symbols": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
-      "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
-      "dev": true
-    },
     "ast-types-flow": {
       "version": "0.0.7",
       "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
       "integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=",
       "dev": true
     },
-    "async": {
-      "version": "2.6.4",
-      "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz",
-      "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==",
-      "dev": true,
-      "requires": {
-        "lodash": "^4.17.14"
-      }
-    },
-    "async-each": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
-      "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
-      "dev": true
-    },
-    "async-limiter": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz",
-      "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==",
-      "dev": true
-    },
     "asynckit": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
       "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
       "dev": true
     },
-    "atob": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
-      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
-      "dev": true
-    },
     "autoprefixer": {
-      "version": "9.8.6",
-      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz",
-      "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==",
+      "version": "10.4.13",
+      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz",
+      "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==",
       "dev": true,
       "requires": {
-        "browserslist": "^4.12.0",
-        "caniuse-lite": "^1.0.30001109",
-        "colorette": "^1.2.1",
+        "browserslist": "^4.21.4",
+        "caniuse-lite": "^1.0.30001426",
+        "fraction.js": "^4.2.0",
         "normalize-range": "^0.1.2",
-        "num2fraction": "^1.2.2",
-        "postcss": "^7.0.32",
-        "postcss-value-parser": "^4.1.0"
+        "picocolors": "^1.0.0",
+        "postcss-value-parser": "^4.2.0"
       }
     },
     "aws-sign2": {
@@ -2365,59 +14694,55 @@
         "ast-types-flow": "0.0.7"
       }
     },
-    "babel-loader": {
-      "version": "8.1.0",
-      "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.1.0.tgz",
-      "integrity": "sha512-7q7nC1tYOrqvUrN3LQK4GwSk/TQorZSOlO9C+RZDZpODgyN4ZlCqE5q9cDsyWOliN+aU9B4JX01xK9eJXowJLw==",
+    "babel-plugin-istanbul": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz",
+      "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==",
       "dev": true,
       "requires": {
-        "find-cache-dir": "^2.1.0",
-        "loader-utils": "^1.4.0",
-        "mkdirp": "^0.5.3",
-        "pify": "^4.0.1",
-        "schema-utils": "^2.6.5"
+        "@babel/helper-plugin-utils": "^7.0.0",
+        "@istanbuljs/load-nyc-config": "^1.0.0",
+        "@istanbuljs/schema": "^0.1.2",
+        "istanbul-lib-instrument": "^5.0.4",
+        "test-exclude": "^6.0.0"
+      }
+    },
+    "babel-plugin-polyfill-corejs2": {
+      "version": "0.3.3",
+      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz",
+      "integrity": "sha512-8hOdmFYFSZhqg2C/JgLUQ+t52o5nirNwaWM2B9LWteozwIvM14VSwdsCAUET10qT+kmySAlseadmfeeSWFCy+Q==",
+      "dev": true,
+      "requires": {
+        "@babel/compat-data": "^7.17.7",
+        "@babel/helper-define-polyfill-provider": "^0.3.3",
+        "semver": "^6.1.1"
       },
       "dependencies": {
-        "find-cache-dir": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
-          "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
-          "dev": true,
-          "requires": {
-            "commondir": "^1.0.1",
-            "make-dir": "^2.0.0",
-            "pkg-dir": "^3.0.0"
-          }
-        },
-        "json5": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
-          "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
-          "dev": true,
-          "requires": {
-            "minimist": "^1.2.0"
-          }
-        },
-        "loader-utils": {
-          "version": "1.4.0",
-          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
-          "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
-          "dev": true,
-          "requires": {
-            "big.js": "^5.2.2",
-            "emojis-list": "^3.0.0",
-            "json5": "^1.0.1"
-          }
+        "semver": {
+          "version": "6.3.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
+          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
+          "dev": true
         }
       }
     },
-    "babel-plugin-dynamic-import-node": {
-      "version": "2.3.3",
-      "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz",
-      "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==",
+    "babel-plugin-polyfill-corejs3": {
+      "version": "0.6.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.6.0.tgz",
+      "integrity": "sha512-+eHqR6OPcBhJOGgsIar7xoAB1GcSwVUA3XjAd7HJNzOXT4wv6/H7KIdA/Nc60cvUlDbKApmqNvD1B1bzOt4nyA==",
       "dev": true,
       "requires": {
-        "object.assign": "^4.1.0"
+        "@babel/helper-define-polyfill-provider": "^0.3.3",
+        "core-js-compat": "^3.25.1"
+      }
+    },
+    "babel-plugin-polyfill-regenerator": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.1.tgz",
+      "integrity": "sha512-NtQGmyQDXjQqQ+IzRkBVwEOz9lQ4zxAQZgoAYEtU9dJjnl1Oc98qnN7jcp+bE7O7aYzVpavXE3/VKXNzUbh7aw==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-define-polyfill-provider": "^0.3.3"
       }
     },
     "balanced-match": {
@@ -2425,61 +14750,6 @@
       "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
       "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
     },
-    "base": {
-      "version": "0.11.2",
-      "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
-      "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
-      "dev": true,
-      "requires": {
-        "cache-base": "^1.0.1",
-        "class-utils": "^0.3.5",
-        "component-emitter": "^1.2.1",
-        "define-property": "^1.0.0",
-        "isobject": "^3.0.1",
-        "mixin-deep": "^1.2.0",
-        "pascalcase": "^0.1.1"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
-          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^1.0.0"
-          }
-        },
-        "is-accessor-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
-          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-data-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
-          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-descriptor": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
-          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
-          "dev": true,
-          "requires": {
-            "is-accessor-descriptor": "^1.0.0",
-            "is-data-descriptor": "^1.0.0",
-            "kind-of": "^6.0.2"
-          }
-        }
-      }
-    },
     "base64-js": {
       "version": "1.3.1",
       "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
@@ -2489,7 +14759,7 @@
     "batch": {
       "version": "0.6.1",
       "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
-      "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=",
+      "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==",
       "dev": true
     },
     "bcrypt-pbkdf": {
@@ -2501,18 +14771,6 @@
         "tweetnacl": "^0.14.3"
       }
     },
-    "bfj": {
-      "version": "6.1.2",
-      "resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.2.tgz",
-      "integrity": "sha512-BmBJa4Lip6BPRINSZ0BPEIfB1wUY/9rwbwvIHQA1KjX9om29B6id0wnWXq7m3bn5JrUVjeOTnVuhPT1FiHwPGw==",
-      "dev": true,
-      "requires": {
-        "bluebird": "^3.5.5",
-        "check-types": "^8.0.3",
-        "hoopy": "^0.1.4",
-        "tryer": "^1.0.1"
-      }
-    },
     "big.js": {
       "version": "5.2.2",
       "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
@@ -2522,43 +14780,66 @@
     "binary-extensions": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz",
-      "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==",
-      "dev": true
+      "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ=="
     },
-    "bluebird": {
-      "version": "3.7.2",
-      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
-      "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==",
-      "dev": true
-    },
-    "bn.js": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.3.tgz",
-      "integrity": "sha512-GkTiFpjFtUzU9CbMeJ5iazkCzGL3jrhzerzZIuqLABjbwRaFt33I9tUdSNryIptM+RxDet6OKm2WnLXzW51KsQ==",
-      "dev": true
-    },
-    "body-parser": {
-      "version": "1.19.0",
-      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
-      "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+    "bl": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+      "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
       "dev": true,
       "requires": {
-        "bytes": "3.1.0",
+        "buffer": "^5.5.0",
+        "inherits": "^2.0.4",
+        "readable-stream": "^3.4.0"
+      },
+      "dependencies": {
+        "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"
+          }
+        },
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "dev": true,
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        }
+      }
+    },
+    "body-parser": {
+      "version": "1.20.1",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
+      "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
+      "dev": true,
+      "requires": {
+        "bytes": "3.1.2",
         "content-type": "~1.0.4",
         "debug": "2.6.9",
-        "depd": "~1.1.2",
-        "http-errors": "1.7.2",
+        "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.7.0",
-        "raw-body": "2.4.0",
-        "type-is": "~1.6.17"
+        "on-finished": "2.4.1",
+        "qs": "6.11.0",
+        "raw-body": "2.5.1",
+        "type-is": "~1.6.18",
+        "unpipe": "1.0.0"
       },
       "dependencies": {
         "bytes": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
-          "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
+          "version": "3.1.2",
+          "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+          "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
           "dev": true
         },
         "debug": {
@@ -2570,41 +14851,36 @@
             "ms": "2.0.0"
           }
         },
-        "iconv-lite": {
-          "version": "0.4.24",
-          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
-          "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
-          "dev": true,
-          "requires": {
-            "safer-buffer": ">= 2.1.2 < 3"
-          }
+        "depd": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+          "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+          "dev": true
         },
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
           "dev": true
         }
       }
     },
-    "bonjour": {
-      "version": "3.5.0",
-      "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz",
-      "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=",
+    "bonjour-service": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.1.0.tgz",
+      "integrity": "sha512-LVRinRB3k1/K0XzZ2p58COnWvkQknIY6sf0zF2rpErvcJXpMBttEPQSxK+HEXSS9VmpZlDoDnQWv8ftJT20B0Q==",
       "dev": true,
       "requires": {
-        "array-flatten": "^2.1.0",
-        "deep-equal": "^1.0.1",
+        "array-flatten": "^2.1.2",
         "dns-equal": "^1.0.0",
-        "dns-txt": "^2.0.2",
-        "multicast-dns": "^6.0.1",
-        "multicast-dns-service-types": "^1.1.0"
+        "fast-deep-equal": "^3.1.3",
+        "multicast-dns": "^7.2.5"
       }
     },
     "boolbase": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
-      "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
+      "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
       "dev": true
     },
     "brace": {
@@ -2625,138 +14901,19 @@
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
       "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
-      "dev": true,
       "requires": {
         "fill-range": "^7.0.1"
       }
     },
-    "brorand": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
-      "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
-      "dev": true
-    },
-    "browserify-aes": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
-      "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
-      "dev": true,
-      "requires": {
-        "buffer-xor": "^1.0.3",
-        "cipher-base": "^1.0.0",
-        "create-hash": "^1.1.0",
-        "evp_bytestokey": "^1.0.3",
-        "inherits": "^2.0.1",
-        "safe-buffer": "^5.0.1"
-      }
-    },
-    "browserify-cipher": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
-      "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
-      "dev": true,
-      "requires": {
-        "browserify-aes": "^1.0.4",
-        "browserify-des": "^1.0.0",
-        "evp_bytestokey": "^1.0.0"
-      }
-    },
-    "browserify-des": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
-      "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
-      "dev": true,
-      "requires": {
-        "cipher-base": "^1.0.1",
-        "des.js": "^1.0.0",
-        "inherits": "^2.0.1",
-        "safe-buffer": "^5.1.2"
-      }
-    },
-    "browserify-rsa": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
-      "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
-      "dev": true,
-      "requires": {
-        "bn.js": "^4.1.0",
-        "randombytes": "^2.0.1"
-      },
-      "dependencies": {
-        "bn.js": {
-          "version": "4.11.9",
-          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
-          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
-          "dev": true
-        }
-      }
-    },
-    "browserify-sign": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz",
-      "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==",
-      "dev": true,
-      "requires": {
-        "bn.js": "^5.1.1",
-        "browserify-rsa": "^4.0.1",
-        "create-hash": "^1.2.0",
-        "create-hmac": "^1.1.7",
-        "elliptic": "^6.5.3",
-        "inherits": "^2.0.4",
-        "parse-asn1": "^5.1.5",
-        "readable-stream": "^3.6.0",
-        "safe-buffer": "^5.2.0"
-      },
-      "dependencies": {
-        "readable-stream": {
-          "version": "3.6.0",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
-          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
-          "dev": true,
-          "requires": {
-            "inherits": "^2.0.3",
-            "string_decoder": "^1.1.1",
-            "util-deprecate": "^1.0.1"
-          }
-        },
-        "safe-buffer": {
-          "version": "5.2.1",
-          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-          "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
-          "dev": true
-        }
-      }
-    },
-    "browserify-zlib": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
-      "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
-      "dev": true,
-      "requires": {
-        "pako": "~1.0.5"
-      }
-    },
     "browserslist": {
-      "version": "4.14.6",
-      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.6.tgz",
-      "integrity": "sha512-zeFYcUo85ENhc/zxHbiIp0LGzzTrE2Pv2JhxvS7kpUb9Q9D38kUX6Bie7pGutJ/5iF5rOxE7CepAuWD56xJ33A==",
-      "dev": true,
+      "version": "4.21.5",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz",
+      "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==",
       "requires": {
-        "caniuse-lite": "^1.0.30001154",
-        "electron-to-chromium": "^1.3.585",
-        "escalade": "^3.1.1",
-        "node-releases": "^1.1.65"
-      }
-    },
-    "buffer": {
-      "version": "4.9.2",
-      "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
-      "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
-      "dev": true,
-      "requires": {
-        "base64-js": "^1.0.2",
-        "ieee754": "^1.1.4",
-        "isarray": "^1.0.0"
+        "caniuse-lite": "^1.0.30001449",
+        "electron-to-chromium": "^1.4.284",
+        "node-releases": "^2.0.8",
+        "update-browserslist-db": "^1.0.10"
       }
     },
     "buffer-from": {
@@ -2765,30 +14922,12 @@
       "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
       "dev": true
     },
-    "buffer-indexof": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz",
-      "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==",
-      "dev": true
-    },
-    "buffer-xor": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
-      "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
-      "dev": true
-    },
     "builtin-modules": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
       "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
       "dev": true
     },
-    "builtin-status-codes": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
-      "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=",
-      "dev": true
-    },
     "builtins": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz",
@@ -2798,7 +14937,7 @@
     "bytes": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
-      "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
+      "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==",
       "dev": true
     },
     "cacache": {
@@ -2827,15 +14966,15 @@
       },
       "dependencies": {
         "glob": {
-          "version": "7.1.6",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+          "version": "7.2.3",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+          "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
           "dev": true,
           "requires": {
             "fs.realpath": "^1.0.0",
             "inflight": "^1.0.4",
             "inherits": "2",
-            "minimatch": "^3.0.4",
+            "minimatch": "^3.1.1",
             "once": "^1.3.0",
             "path-is-absolute": "^1.0.0"
           }
@@ -2848,85 +14987,37 @@
         }
       }
     },
-    "cache-base": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
-      "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
-      "dev": true,
-      "requires": {
-        "collection-visit": "^1.0.0",
-        "component-emitter": "^1.2.1",
-        "get-value": "^2.0.6",
-        "has-value": "^1.0.0",
-        "isobject": "^3.0.1",
-        "set-value": "^2.0.0",
-        "to-object-path": "^0.3.0",
-        "union-value": "^1.0.0",
-        "unset-value": "^1.0.0"
-      }
-    },
     "call-bind": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz",
-      "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+      "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
       "dev": true,
       "requires": {
         "function-bind": "^1.1.1",
-        "get-intrinsic": "^1.0.0"
-      }
-    },
-    "caller-callsite": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
-      "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=",
-      "dev": true,
-      "requires": {
-        "callsites": "^2.0.0"
-      }
-    },
-    "caller-path": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz",
-      "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=",
-      "dev": true,
-      "requires": {
-        "caller-callsite": "^2.0.0"
+        "get-intrinsic": "^1.0.2"
       }
     },
     "callsites": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz",
-      "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
       "dev": true
     },
     "camelcase": {
       "version": "5.3.1",
       "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
-      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
-    },
-    "caniuse-api": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz",
-      "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==",
-      "dev": true,
-      "requires": {
-        "browserslist": "^4.0.0",
-        "caniuse-lite": "^1.0.0",
-        "lodash.memoize": "^4.1.2",
-        "lodash.uniq": "^4.5.0"
-      }
+      "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
+      "dev": true
     },
     "caniuse-lite": {
-      "version": "1.0.30001156",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001156.tgz",
-      "integrity": "sha512-z7qztybA2eFZTB6Z3yvaQBIoJpQtsewRD74adw2UbRWwsRq3jIPvgrQGawBMbfafekQaD21FWuXNcywtTDGGCw==",
-      "dev": true
+      "version": "1.0.30001451",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001451.tgz",
+      "integrity": "sha512-XY7UbUpGRatZzoRft//5xOa69/1iGJRBlrieH6QYrkKLIFn3m7OVEJ81dSrKoy2BnKsdbX5cLrOispZNYo9v2w=="
     },
     "canonical-path": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/canonical-path/-/canonical-path-1.0.0.tgz",
-      "integrity": "sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg==",
-      "dev": true
+      "integrity": "sha512-feylzsbDxi1gPZ1IjystzIQZagYYLvfKrSuygUCgf7z6x790VEzze5QEkdSV1U58RA7Hi0+v6fv4K54atOzATg=="
     },
     "caseless": {
       "version": "0.12.0",
@@ -2950,26 +15041,19 @@
       "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
       "dev": true
     },
-    "check-types": {
-      "version": "8.0.3",
-      "resolved": "https://registry.npmjs.org/check-types/-/check-types-8.0.3.tgz",
-      "integrity": "sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ==",
-      "dev": true
-    },
     "chokidar": {
-      "version": "3.4.3",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.3.tgz",
-      "integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==",
-      "dev": true,
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+      "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
       "requires": {
-        "anymatch": "~3.1.1",
+        "anymatch": "~3.1.2",
         "braces": "~3.0.2",
-        "fsevents": "~2.1.2",
-        "glob-parent": "~5.1.0",
+        "fsevents": "~2.3.2",
+        "glob-parent": "~5.1.2",
         "is-binary-path": "~2.1.0",
         "is-glob": "~4.0.1",
         "normalize-path": "~3.0.0",
-        "readdirp": "~3.5.0"
+        "readdirp": "~3.6.0"
       }
     },
     "chownr": {
@@ -2979,53 +15063,11 @@
       "dev": true
     },
     "chrome-trace-event": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz",
-      "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==",
-      "dev": true,
-      "requires": {
-        "tslib": "^1.9.0"
-      }
-    },
-    "cipher-base": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
-      "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.1",
-        "safe-buffer": "^5.0.1"
-      }
-    },
-    "circular-dependency-plugin": {
-      "version": "5.2.0",
-      "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-5.2.0.tgz",
-      "integrity": "sha512-7p4Kn/gffhQaavNfyDFg7LS5S/UT1JAjyGd4UqR2+jzoYF02eDkj0Ec3+48TsIa4zghjLY87nQHIh/ecK9qLdw==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz",
+      "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==",
       "dev": true
     },
-    "class-utils": {
-      "version": "0.3.6",
-      "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
-      "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
-      "dev": true,
-      "requires": {
-        "arr-union": "^3.1.0",
-        "define-property": "^0.2.5",
-        "isobject": "^3.0.0",
-        "static-extend": "^0.1.1"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "0.2.5",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^0.1.0"
-          }
-        }
-      }
-    },
     "clean-stack": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
@@ -3042,9 +15084,9 @@
       }
     },
     "cli-spinners": {
-      "version": "2.5.0",
-      "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.5.0.tgz",
-      "integrity": "sha512-PC+AmIuK04E6aeSs/pUccSujsTzBhu4HzC2dL+CfJB/Jcc2qTRbEwZQDfIUpt2Xl8BodYBEq8w4fc0kU2I9DjQ==",
+      "version": "2.6.1",
+      "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz",
+      "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==",
       "dev": true
     },
     "cli-width": {
@@ -3054,36 +15096,42 @@
       "dev": true
     },
     "cliui": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
-      "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
+      "version": "7.0.4",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+      "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
       "requires": {
         "string-width": "^4.2.0",
         "strip-ansi": "^6.0.0",
-        "wrap-ansi": "^6.2.0"
+        "wrap-ansi": "^7.0.0"
       }
     },
     "clone": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
-      "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+      "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
       "dev": true
     },
-    "coa": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz",
-      "integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==",
+    "clone-deep": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
+      "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==",
       "dev": true,
       "requires": {
-        "@types/q": "^1.5.1",
-        "chalk": "^2.4.1",
-        "q": "^1.1.2"
+        "is-plain-object": "^2.0.4",
+        "kind-of": "^6.0.2",
+        "shallow-clone": "^3.0.0"
       }
     },
+    "code-point-at": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+      "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==",
+      "dev": true
+    },
     "codelyzer": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-6.0.1.tgz",
-      "integrity": "sha512-cOyGQgMdhnRYtW2xrJUNrNYDjEgwQ+BrE2y93Bwz3h4DJ6vJRLfupemU5N3pbYsUlBHJf0u1j1UGk+NLW4d97g==",
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-6.0.2.tgz",
+      "integrity": "sha512-v3+E0Ucu2xWJMOJ2fA/q9pDT/hlxHftHGPUay1/1cTgyPV5JTHFdO9hqo837Sx2s9vKBMTt5gO+lhF95PO6J+g==",
       "dev": true,
       "requires": {
         "@angular/compiler": "9.0.0",
@@ -3106,42 +15154,30 @@
           "version": "9.0.0",
           "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-9.0.0.tgz",
           "integrity": "sha512-ctjwuntPfZZT2mNj2NDIVu51t9cvbhl/16epc5xEwyzyDt76pX9UgwvY+MbXrf/C/FWwdtmNtfP698BKI+9leQ==",
-          "dev": true
+          "dev": true,
+          "requires": {}
         },
         "@angular/core": {
           "version": "9.0.0",
           "resolved": "https://registry.npmjs.org/@angular/core/-/core-9.0.0.tgz",
           "integrity": "sha512-6Pxgsrf0qF9iFFqmIcWmjJGkkCaCm6V5QNnxMy2KloO3SDq6QuMVRbN9RtC8Urmo25LP+eZ6ZgYqFYpdD8Hd9w==",
-          "dev": true
+          "dev": true,
+          "requires": {}
         },
         "sprintf-js": {
           "version": "1.1.2",
           "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz",
           "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==",
           "dev": true
+        },
+        "tslib": {
+          "version": "1.14.1",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+          "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+          "dev": true
         }
       }
     },
-    "collection-visit": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
-      "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
-      "dev": true,
-      "requires": {
-        "map-visit": "^1.0.0",
-        "object-visit": "^1.0.0"
-      }
-    },
-    "color": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz",
-      "integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==",
-      "dev": true,
-      "requires": {
-        "color-convert": "^1.9.1",
-        "color-string": "^1.5.4"
-      }
-    },
     "color-convert": {
       "version": "1.9.3",
       "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -3155,20 +15191,10 @@
       "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
       "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
     },
-    "color-string": {
-      "version": "1.5.4",
-      "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.4.tgz",
-      "integrity": "sha512-57yF5yt8Xa3czSEW1jfQDE79Idk0+AkN/4KWad6tbdxUmAs3MvjxlWSWD4deYytcRfoZ9nhKyFl1kj5tBvidbw==",
-      "dev": true,
-      "requires": {
-        "color-name": "^1.0.0",
-        "simple-swizzle": "^0.2.2"
-      }
-    },
     "colorette": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz",
-      "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==",
+      "version": "2.0.19",
+      "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
+      "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
       "dev": true
     },
     "combined-stream": {
@@ -3189,24 +15215,9 @@
     "commondir": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
-      "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
+      "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==",
       "dev": true
     },
-    "component-emitter": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
-      "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
-      "dev": true
-    },
-    "compose-function": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/compose-function/-/compose-function-3.0.3.tgz",
-      "integrity": "sha1-ntZ18TzFRQHTCVCkhv9qe6OrGF8=",
-      "dev": true,
-      "requires": {
-        "arity-n": "^1.0.4"
-      }
-    },
     "compressible": {
       "version": "2.0.18",
       "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
@@ -3243,7 +15254,7 @@
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
           "dev": true
         }
       }
@@ -3253,49 +15264,39 @@
       "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
       "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
     },
-    "concat-stream": {
-      "version": "1.6.2",
-      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
-      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
-      "dev": true,
-      "requires": {
-        "buffer-from": "^1.0.0",
-        "inherits": "^2.0.3",
-        "readable-stream": "^2.2.2",
-        "typedarray": "^0.0.6"
-      }
-    },
     "connect-history-api-fallback": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz",
-      "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz",
+      "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==",
       "dev": true
     },
-    "console-browserify": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz",
-      "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==",
-      "dev": true
-    },
-    "constants-browserify": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
-      "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=",
+    "console-control-strings": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+      "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
       "dev": true
     },
     "content-disposition": {
-      "version": "0.5.3",
-      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
-      "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+      "version": "0.5.4",
+      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
+      "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
       "dev": true,
       "requires": {
-        "safe-buffer": "5.1.2"
+        "safe-buffer": "5.2.1"
+      },
+      "dependencies": {
+        "safe-buffer": {
+          "version": "5.2.1",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+          "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+          "dev": true
+        }
       }
     },
     "content-type": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
-      "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
+      "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
       "dev": true
     },
     "convert-source-map": {
@@ -3307,113 +15308,63 @@
       }
     },
     "cookie": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
-      "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
+      "version": "0.5.0",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
+      "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
       "dev": true
     },
     "cookie-signature": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
-      "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
+      "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
       "dev": true
     },
-    "copy-concurrently": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz",
-      "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==",
+    "copy-anything": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz",
+      "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==",
       "dev": true,
       "requires": {
-        "aproba": "^1.1.1",
-        "fs-write-stream-atomic": "^1.0.8",
-        "iferr": "^0.1.5",
-        "mkdirp": "^0.5.1",
-        "rimraf": "^2.5.4",
-        "run-queue": "^1.0.0"
-      },
-      "dependencies": {
-        "glob": {
-          "version": "7.1.6",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
-        "rimraf": {
-          "version": "2.7.1",
-          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
-          "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
-          "dev": true,
-          "requires": {
-            "glob": "^7.1.3"
-          }
-        }
+        "is-what": "^3.14.1"
       }
     },
-    "copy-descriptor": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
-      "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
-      "dev": true
-    },
     "copy-webpack-plugin": {
-      "version": "6.0.3",
-      "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-6.0.3.tgz",
-      "integrity": "sha512-q5m6Vz4elsuyVEIUXr7wJdIdePWTubsqVbEMvf1WQnHGv0Q+9yPRu7MtYFPt+GBOXRav9lvIINifTQ1vSCs+eA==",
+      "version": "11.0.0",
+      "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz",
+      "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==",
       "dev": true,
       "requires": {
-        "cacache": "^15.0.4",
-        "fast-glob": "^3.2.4",
-        "find-cache-dir": "^3.3.1",
-        "glob-parent": "^5.1.1",
-        "globby": "^11.0.1",
-        "loader-utils": "^2.0.0",
+        "fast-glob": "^3.2.11",
+        "glob-parent": "^6.0.1",
+        "globby": "^13.1.1",
         "normalize-path": "^3.0.0",
-        "p-limit": "^3.0.1",
-        "schema-utils": "^2.7.0",
-        "serialize-javascript": "^4.0.0",
-        "webpack-sources": "^1.4.3"
+        "schema-utils": "^4.0.0",
+        "serialize-javascript": "^6.0.0"
       },
       "dependencies": {
-        "p-limit": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz",
-          "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==",
+        "glob-parent": {
+          "version": "6.0.2",
+          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+          "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
           "dev": true,
           "requires": {
-            "p-try": "^2.0.0"
+            "is-glob": "^4.0.3"
           }
         }
       }
     },
     "core-js": {
-      "version": "3.6.5",
-      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz",
-      "integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA=="
+      "version": "3.8.3",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.8.3.tgz",
+      "integrity": "sha512-KPYXeVZYemC2TkNEkX/01I+7yd+nX3KddKwZ1Ww7SKWdI2wQprSgLmrTddT8nw92AjEklTsPBoSdQBhbI1bQ6Q=="
     },
     "core-js-compat": {
-      "version": "3.6.5",
-      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz",
-      "integrity": "sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==",
+      "version": "3.27.2",
+      "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.27.2.tgz",
+      "integrity": "sha512-welaYuF7ZtbYKGrIy7y3eb40d37rG1FvzEOfe7hSLd2iD6duMDqUhRfSvCGyC46HhR6Y8JXXdZ2lnRUMkPBpvg==",
       "dev": true,
       "requires": {
-        "browserslist": "^4.8.5",
-        "semver": "7.0.0"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "7.0.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz",
-          "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==",
-          "dev": true
-        }
+        "browserslist": "^4.21.4"
       }
     },
     "core-util-is": {
@@ -3423,191 +15374,140 @@
       "dev": true
     },
     "cosmiconfig": {
-      "version": "5.2.1",
-      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
-      "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==",
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
+      "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
       "dev": true,
       "requires": {
-        "import-fresh": "^2.0.0",
-        "is-directory": "^0.3.1",
-        "js-yaml": "^3.13.1",
-        "parse-json": "^4.0.0"
+        "@types/parse-json": "^4.0.0",
+        "import-fresh": "^3.2.1",
+        "parse-json": "^5.0.0",
+        "path-type": "^4.0.0",
+        "yaml": "^1.10.0"
       }
     },
-    "create-ecdh": {
-      "version": "4.0.4",
-      "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
-      "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
+    "critters": {
+      "version": "0.0.16",
+      "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.16.tgz",
+      "integrity": "sha512-JwjgmO6i3y6RWtLYmXwO5jMd+maZt8Tnfu7VVISmEWyQqfLpB8soBswf8/2bu6SBXxtKA68Al3c+qIG1ApT68A==",
       "dev": true,
       "requires": {
-        "bn.js": "^4.1.0",
-        "elliptic": "^6.5.3"
+        "chalk": "^4.1.0",
+        "css-select": "^4.2.0",
+        "parse5": "^6.0.1",
+        "parse5-htmlparser2-tree-adapter": "^6.0.1",
+        "postcss": "^8.3.7",
+        "pretty-bytes": "^5.3.0"
       },
       "dependencies": {
-        "bn.js": {
-          "version": "4.11.9",
-          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
-          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
           "dev": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "parse5": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
+          "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
         }
       }
     },
-    "create-hash": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
-      "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
-      "dev": true,
-      "requires": {
-        "cipher-base": "^1.0.1",
-        "inherits": "^2.0.1",
-        "md5.js": "^1.3.4",
-        "ripemd160": "^2.0.1",
-        "sha.js": "^2.4.0"
-      }
-    },
-    "create-hmac": {
-      "version": "1.1.7",
-      "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
-      "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
-      "dev": true,
-      "requires": {
-        "cipher-base": "^1.0.3",
-        "create-hash": "^1.1.0",
-        "inherits": "^2.0.1",
-        "ripemd160": "^2.0.0",
-        "safe-buffer": "^5.0.1",
-        "sha.js": "^2.4.8"
-      }
-    },
     "cross-spawn": {
-      "version": "6.0.5",
-      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
-      "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
+      "version": "7.0.3",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
+      "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
       "dev": true,
       "requires": {
-        "nice-try": "^1.0.4",
-        "path-key": "^2.0.1",
-        "semver": "^5.5.0",
-        "shebang-command": "^1.2.0",
-        "which": "^1.2.9"
-      }
-    },
-    "crypto-browserify": {
-      "version": "3.12.0",
-      "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
-      "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
-      "dev": true,
-      "requires": {
-        "browserify-cipher": "^1.0.0",
-        "browserify-sign": "^4.0.0",
-        "create-ecdh": "^4.0.0",
-        "create-hash": "^1.1.0",
-        "create-hmac": "^1.1.0",
-        "diffie-hellman": "^5.0.0",
-        "inherits": "^2.0.1",
-        "pbkdf2": "^3.0.3",
-        "public-encrypt": "^4.0.0",
-        "randombytes": "^2.0.0",
-        "randomfill": "^1.0.3"
-      }
-    },
-    "css": {
-      "version": "2.2.4",
-      "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz",
-      "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.3",
-        "source-map": "^0.6.1",
-        "source-map-resolve": "^0.5.2",
-        "urix": "^0.1.0"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
-      }
-    },
-    "css-color-names": {
-      "version": "0.0.4",
-      "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
-      "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=",
-      "dev": true
-    },
-    "css-declaration-sorter": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-4.0.1.tgz",
-      "integrity": "sha512-BcxQSKTSEEQUftYpBVnsH4SF05NTuBokb19/sBt6asXGKZ/6VP7PLG1CBCkFDYOnhXhPh0jMhO6xZ71oYHXHBA==",
-      "dev": true,
-      "requires": {
-        "postcss": "^7.0.1",
-        "timsort": "^0.3.0"
+        "path-key": "^3.1.0",
+        "shebang-command": "^2.0.0",
+        "which": "^2.0.1"
       }
     },
     "css-loader": {
-      "version": "4.2.2",
-      "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-4.2.2.tgz",
-      "integrity": "sha512-omVGsTkZPVwVRpckeUnLshPp12KsmMSLqYxs12+RzM9jRR5Y+Idn/tBffjXRvOE+qW7if24cuceFJqYR5FmGBg==",
+      "version": "6.7.3",
+      "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.3.tgz",
+      "integrity": "sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==",
       "dev": true,
       "requires": {
-        "camelcase": "^6.0.0",
-        "cssesc": "^3.0.0",
-        "icss-utils": "^4.1.1",
-        "loader-utils": "^2.0.0",
-        "postcss": "^7.0.32",
-        "postcss-modules-extract-imports": "^2.0.0",
-        "postcss-modules-local-by-default": "^3.0.3",
-        "postcss-modules-scope": "^2.2.0",
-        "postcss-modules-values": "^3.0.0",
-        "postcss-value-parser": "^4.1.0",
-        "schema-utils": "^2.7.0",
-        "semver": "^7.3.2"
+        "icss-utils": "^5.1.0",
+        "postcss": "^8.4.19",
+        "postcss-modules-extract-imports": "^3.0.0",
+        "postcss-modules-local-by-default": "^4.0.0",
+        "postcss-modules-scope": "^3.0.0",
+        "postcss-modules-values": "^4.0.0",
+        "postcss-value-parser": "^4.2.0",
+        "semver": "^7.3.8"
       },
       "dependencies": {
-        "camelcase": {
-          "version": "6.2.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz",
-          "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==",
-          "dev": true
-        },
         "semver": {
-          "version": "7.3.2",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
-          "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
-          "dev": true
+          "version": "7.3.8",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+          "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
         }
       }
     },
-    "css-parse": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-2.0.0.tgz",
-      "integrity": "sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q=",
-      "dev": true,
-      "requires": {
-        "css": "^2.0.0"
-      }
-    },
     "css-select": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz",
-      "integrity": "sha512-Dqk7LQKpwLoH3VovzZnkzegqNSuAziQyNZUcrdDM401iY+R5NkGBXGmtO05/yaXQziALuPogeG0b7UAgjnTJTQ==",
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz",
+      "integrity": "sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==",
       "dev": true,
       "requires": {
         "boolbase": "^1.0.0",
-        "css-what": "^3.2.1",
-        "domutils": "^1.7.0",
-        "nth-check": "^1.0.2"
+        "css-what": "^6.0.1",
+        "domhandler": "^4.3.1",
+        "domutils": "^2.8.0",
+        "nth-check": "^2.0.1"
       }
     },
-    "css-select-base-adapter": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/css-select-base-adapter/-/css-select-base-adapter-0.1.1.tgz",
-      "integrity": "sha512-jQVeeRG70QI08vSTwf1jHxp74JoZsr2XSgETae8/xC8ovSnL2WF87GTLO86Sbwdt2lK4Umg4HnnwMO4YF3Ce7w==",
-      "dev": true
-    },
     "css-selector-tokenizer": {
       "version": "0.7.3",
       "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz",
@@ -3618,28 +15518,10 @@
         "fastparse": "^1.1.2"
       }
     },
-    "css-tree": {
-      "version": "1.0.0-alpha.37",
-      "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.37.tgz",
-      "integrity": "sha512-DMxWJg0rnz7UgxKT0Q1HU/L9BeJI0M6ksor0OgqOnF+aRCDWg/N2641HmVyU9KVIu0OVVWOb2IpC9A+BJRnejg==",
-      "dev": true,
-      "requires": {
-        "mdn-data": "2.0.4",
-        "source-map": "^0.6.1"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
-      }
-    },
     "css-what": {
-      "version": "3.4.2",
-      "resolved": "https://registry.npmjs.org/css-what/-/css-what-3.4.2.tgz",
-      "integrity": "sha512-ACUm3L0/jiZTqfzRM3Hi9Q8eZqd6IK37mMWPLz9PJxkLWllYeRf+EHUSHYEtFop2Eqytaq1FizFVh7XfBnXCDQ==",
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz",
+      "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==",
       "dev": true
     },
     "cssauron": {
@@ -3657,132 +15539,6 @@
       "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
       "dev": true
     },
-    "cssnano": {
-      "version": "4.1.10",
-      "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-4.1.10.tgz",
-      "integrity": "sha512-5wny+F6H4/8RgNlaqab4ktc3e0/blKutmq8yNlBFXA//nSFFAqAngjNVRzUvCgYROULmZZUoosL/KSoZo5aUaQ==",
-      "dev": true,
-      "requires": {
-        "cosmiconfig": "^5.0.0",
-        "cssnano-preset-default": "^4.0.7",
-        "is-resolvable": "^1.0.0",
-        "postcss": "^7.0.0"
-      }
-    },
-    "cssnano-preset-default": {
-      "version": "4.0.7",
-      "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-4.0.7.tgz",
-      "integrity": "sha512-x0YHHx2h6p0fCl1zY9L9roD7rnlltugGu7zXSKQx6k2rYw0Hi3IqxcoAGF7u9Q5w1nt7vK0ulxV8Lo+EvllGsA==",
-      "dev": true,
-      "requires": {
-        "css-declaration-sorter": "^4.0.1",
-        "cssnano-util-raw-cache": "^4.0.1",
-        "postcss": "^7.0.0",
-        "postcss-calc": "^7.0.1",
-        "postcss-colormin": "^4.0.3",
-        "postcss-convert-values": "^4.0.1",
-        "postcss-discard-comments": "^4.0.2",
-        "postcss-discard-duplicates": "^4.0.2",
-        "postcss-discard-empty": "^4.0.1",
-        "postcss-discard-overridden": "^4.0.1",
-        "postcss-merge-longhand": "^4.0.11",
-        "postcss-merge-rules": "^4.0.3",
-        "postcss-minify-font-values": "^4.0.2",
-        "postcss-minify-gradients": "^4.0.2",
-        "postcss-minify-params": "^4.0.2",
-        "postcss-minify-selectors": "^4.0.2",
-        "postcss-normalize-charset": "^4.0.1",
-        "postcss-normalize-display-values": "^4.0.2",
-        "postcss-normalize-positions": "^4.0.2",
-        "postcss-normalize-repeat-style": "^4.0.2",
-        "postcss-normalize-string": "^4.0.2",
-        "postcss-normalize-timing-functions": "^4.0.2",
-        "postcss-normalize-unicode": "^4.0.1",
-        "postcss-normalize-url": "^4.0.1",
-        "postcss-normalize-whitespace": "^4.0.2",
-        "postcss-ordered-values": "^4.1.2",
-        "postcss-reduce-initial": "^4.0.3",
-        "postcss-reduce-transforms": "^4.0.2",
-        "postcss-svgo": "^4.0.2",
-        "postcss-unique-selectors": "^4.0.1"
-      }
-    },
-    "cssnano-util-get-arguments": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/cssnano-util-get-arguments/-/cssnano-util-get-arguments-4.0.0.tgz",
-      "integrity": "sha1-7ToIKZ8h11dBsg87gfGU7UnMFQ8=",
-      "dev": true
-    },
-    "cssnano-util-get-match": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/cssnano-util-get-match/-/cssnano-util-get-match-4.0.0.tgz",
-      "integrity": "sha1-wOTKB/U4a7F+xeUiULT1lhNlFW0=",
-      "dev": true
-    },
-    "cssnano-util-raw-cache": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/cssnano-util-raw-cache/-/cssnano-util-raw-cache-4.0.1.tgz",
-      "integrity": "sha512-qLuYtWK2b2Dy55I8ZX3ky1Z16WYsx544Q0UWViebptpwn/xDBmog2TLg4f+DBMg1rJ6JDWtn96WHbOKDWt1WQA==",
-      "dev": true,
-      "requires": {
-        "postcss": "^7.0.0"
-      }
-    },
-    "cssnano-util-same-parent": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/cssnano-util-same-parent/-/cssnano-util-same-parent-4.0.1.tgz",
-      "integrity": "sha512-WcKx5OY+KoSIAxBW6UBBRay1U6vkYheCdjyVNDm85zt5K9mHoGOfsOsqIszfAqrQQFIIKgjh2+FDgIj/zsl21Q==",
-      "dev": true
-    },
-    "csso": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/csso/-/csso-4.1.0.tgz",
-      "integrity": "sha512-h+6w/W1WqXaJA4tb1dk7r5tVbOm97MsKxzwnvOR04UQ6GILroryjMWu3pmCCtL2mLaEStQ0fZgeGiy99mo7iyg==",
-      "dev": true,
-      "requires": {
-        "css-tree": "^1.0.0"
-      },
-      "dependencies": {
-        "css-tree": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0.tgz",
-          "integrity": "sha512-CdVYz/Yuqw0VdKhXPBIgi8DO3NicJVYZNWeX9XcIuSp9ZoFT5IcleVRW07O5rMjdcx1mb+MEJPknTTEW7DdsYw==",
-          "dev": true,
-          "requires": {
-            "mdn-data": "2.0.12",
-            "source-map": "^0.6.1"
-          }
-        },
-        "mdn-data": {
-          "version": "2.0.12",
-          "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.12.tgz",
-          "integrity": "sha512-ULbAlgzVb8IqZ0Hsxm6hHSlQl3Jckst2YEQS7fODu9ilNWy2LvcoSY7TRFIktABP2mdppBioc66va90T+NUs8Q==",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
-      }
-    },
-    "cyclist": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz",
-      "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=",
-      "dev": true
-    },
-    "d": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
-      "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
-      "dev": true,
-      "requires": {
-        "es5-ext": "^0.10.50",
-        "type": "^1.0.1"
-      }
-    },
     "damerau-levenshtein": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.6.tgz",
@@ -3798,17 +15554,6 @@
         "assert-plus": "^1.0.0"
       }
     },
-    "data-urls": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
-      "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==",
-      "dev": true,
-      "requires": {
-        "abab": "^2.0.3",
-        "whatwg-mimetype": "^2.3.0",
-        "whatwg-url": "^8.0.0"
-      }
-    },
     "date-fns": {
       "version": "1.30.1",
       "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz",
@@ -3822,191 +15567,29 @@
         "ms": "2.1.2"
       }
     },
-    "debuglog": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz",
-      "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=",
-      "dev": true
-    },
-    "decamelize": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
-      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
-    },
-    "decode-uri-component": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
-      "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
-      "dev": true
-    },
-    "deep-equal": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz",
-      "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==",
-      "dev": true,
-      "requires": {
-        "is-arguments": "^1.0.4",
-        "is-date-object": "^1.0.1",
-        "is-regex": "^1.0.4",
-        "object-is": "^1.0.1",
-        "object-keys": "^1.1.1",
-        "regexp.prototype.flags": "^1.2.0"
-      }
-    },
     "default-gateway": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz",
-      "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==",
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz",
+      "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==",
       "dev": true,
       "requires": {
-        "execa": "^1.0.0",
-        "ip-regex": "^2.1.0"
+        "execa": "^5.0.0"
       }
     },
     "defaults": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
-      "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=",
+      "integrity": "sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==",
       "dev": true,
       "requires": {
         "clone": "^1.0.2"
-      },
-      "dependencies": {
-        "clone": {
-          "version": "1.0.4",
-          "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
-          "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
-          "dev": true
-        }
       }
     },
-    "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==",
-      "dev": true,
-      "requires": {
-        "object-keys": "^1.0.12"
-      }
-    },
-    "define-property": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
-      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
-      "dev": true,
-      "requires": {
-        "is-descriptor": "^1.0.2",
-        "isobject": "^3.0.1"
-      },
-      "dependencies": {
-        "is-accessor-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
-          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-data-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
-          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-descriptor": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
-          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
-          "dev": true,
-          "requires": {
-            "is-accessor-descriptor": "^1.0.0",
-            "is-data-descriptor": "^1.0.0",
-            "kind-of": "^6.0.2"
-          }
-        }
-      }
-    },
-    "del": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz",
-      "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==",
-      "dev": true,
-      "requires": {
-        "@types/glob": "^7.1.1",
-        "globby": "^6.1.0",
-        "is-path-cwd": "^2.0.0",
-        "is-path-in-cwd": "^2.0.0",
-        "p-map": "^2.0.0",
-        "pify": "^4.0.1",
-        "rimraf": "^2.6.3"
-      },
-      "dependencies": {
-        "array-union": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
-          "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
-          "dev": true,
-          "requires": {
-            "array-uniq": "^1.0.1"
-          }
-        },
-        "globby": {
-          "version": "6.1.0",
-          "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz",
-          "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=",
-          "dev": true,
-          "requires": {
-            "array-union": "^1.0.1",
-            "glob": "^7.0.3",
-            "object-assign": "^4.0.1",
-            "pify": "^2.0.0",
-            "pinkie-promise": "^2.0.0"
-          },
-          "dependencies": {
-            "pify": {
-              "version": "2.3.0",
-              "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-              "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
-              "dev": true
-            }
-          }
-        },
-        "p-map": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
-          "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==",
-          "dev": true
-        },
-        "rimraf": {
-          "version": "2.7.1",
-          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
-          "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
-          "dev": true,
-          "requires": {
-            "glob": "^7.1.3"
-          },
-          "dependencies": {
-            "glob": {
-              "version": "7.1.6",
-              "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-              "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-              "dev": true,
-              "requires": {
-                "fs.realpath": "^1.0.0",
-                "inflight": "^1.0.4",
-                "inherits": "2",
-                "minimatch": "^3.0.4",
-                "once": "^1.3.0",
-                "path-is-absolute": "^1.0.0"
-              }
-            }
-          }
-        }
-      }
+    "define-lazy-prop": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
+      "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
+      "dev": true
     },
     "delayed-stream": {
       "version": "1.0.0",
@@ -4014,6 +15597,12 @@
       "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
       "dev": true
     },
+    "delegates": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+      "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
+      "dev": true
+    },
     "depd": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
@@ -4023,66 +15612,26 @@
     "dependency-graph": {
       "version": "0.7.2",
       "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.7.2.tgz",
-      "integrity": "sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ==",
-      "dev": true
-    },
-    "des.js": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz",
-      "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.1",
-        "minimalistic-assert": "^1.0.0"
-      }
+      "integrity": "sha512-KqtH4/EZdtdfWX0p6MGP9jljvxSY6msy/pRUD4jgNwVpv3v1QmNLlsB3LDSSUg79BRVSn7jI1QPRtArGABovAQ=="
     },
     "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==",
       "dev": true
     },
     "detect-node": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz",
-      "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
+      "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
       "dev": true
     },
-    "dezalgo": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz",
-      "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=",
-      "dev": true,
-      "requires": {
-        "asap": "^2.0.0",
-        "wrappy": "1"
-      }
-    },
     "diff": {
       "version": "4.0.2",
       "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
       "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
       "dev": true
     },
-    "diffie-hellman": {
-      "version": "5.0.3",
-      "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
-      "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
-      "dev": true,
-      "requires": {
-        "bn.js": "^4.1.0",
-        "miller-rabin": "^4.0.0",
-        "randombytes": "^2.0.0"
-      },
-      "dependencies": {
-        "bn.js": {
-          "version": "4.11.9",
-          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
-          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
-          "dev": true
-        }
-      }
-    },
     "dir-glob": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@@ -4095,57 +15644,43 @@
     "dns-equal": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
-      "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=",
+      "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==",
       "dev": true
     },
     "dns-packet": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.1.tgz",
-      "integrity": "sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==",
+      "version": "5.4.0",
+      "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.4.0.tgz",
+      "integrity": "sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g==",
       "dev": true,
       "requires": {
-        "ip": "^1.1.0",
-        "safe-buffer": "^5.0.1"
-      }
-    },
-    "dns-txt": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz",
-      "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=",
-      "dev": true,
-      "requires": {
-        "buffer-indexof": "^1.0.0"
+        "@leichtgewicht/ip-codec": "^2.0.1"
       }
     },
     "dom-serializer": {
-      "version": "0.2.2",
-      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
-      "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
+      "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
       "dev": true,
       "requires": {
         "domelementtype": "^2.0.1",
+        "domhandler": "^4.2.0",
         "entities": "^2.0.0"
-      },
-      "dependencies": {
-        "domelementtype": {
-          "version": "2.0.2",
-          "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.2.tgz",
-          "integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==",
-          "dev": true
-        }
       }
     },
-    "domain-browser": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
-      "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
+    "domelementtype": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+      "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
       "dev": true
     },
-    "domelementtype": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
-      "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
-      "dev": true
+    "domhandler": {
+      "version": "4.3.1",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
+      "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
+      "dev": true,
+      "requires": {
+        "domelementtype": "^2.2.0"
+      }
     },
     "domino": {
       "version": "2.1.6",
@@ -4153,22 +15688,14 @@
       "integrity": "sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ=="
     },
     "domutils": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
-      "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
+      "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
       "dev": true,
       "requires": {
-        "dom-serializer": "0",
-        "domelementtype": "1"
-      }
-    },
-    "dot-prop": {
-      "version": "5.3.0",
-      "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz",
-      "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
-      "dev": true,
-      "requires": {
-        "is-obj": "^2.0.0"
+        "dom-serializer": "^1.0.1",
+        "domelementtype": "^2.2.0",
+        "domhandler": "^4.2.0"
       }
     },
     "duplexer": {
@@ -4177,18 +15704,6 @@
       "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==",
       "dev": true
     },
-    "duplexify": {
-      "version": "3.7.1",
-      "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
-      "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==",
-      "dev": true,
-      "requires": {
-        "end-of-stream": "^1.0.0",
-        "inherits": "^2.0.1",
-        "readable-stream": "^2.0.0",
-        "stream-shift": "^1.0.0"
-      }
-    },
     "ecc-jsbn": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
@@ -4202,43 +15717,13 @@
     "ee-first": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
-      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
-      "dev": true
-    },
-    "ejs": {
-      "version": "2.7.4",
-      "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz",
-      "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==",
+      "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
       "dev": true
     },
     "electron-to-chromium": {
-      "version": "1.3.588",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.588.tgz",
-      "integrity": "sha512-0zr+ZfytnLeJZxGgmEpPTcItu5Mm4A5zHPZXLfHcGp0mdsk95rmD7ePNewYtK1yIdLbk8Z1U2oTRRfOtR4gbYg==",
-      "dev": true
-    },
-    "elliptic": {
-      "version": "6.5.3",
-      "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
-      "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
-      "dev": true,
-      "requires": {
-        "bn.js": "^4.4.0",
-        "brorand": "^1.0.1",
-        "hash.js": "^1.0.0",
-        "hmac-drbg": "^1.0.0",
-        "inherits": "^2.0.1",
-        "minimalistic-assert": "^1.0.0",
-        "minimalistic-crypto-utils": "^1.0.0"
-      },
-      "dependencies": {
-        "bn.js": {
-          "version": "4.11.9",
-          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
-          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
-          "dev": true
-        }
-      }
+      "version": "1.4.292",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.292.tgz",
+      "integrity": "sha512-ESWOSyJy5odDlE8wvh5NNAMORv4r6assPwIPGHEMWrWD0SONXcG/xT+9aD9CQyeRwyYDPo6dJT4Bbeg5uevVQQ=="
     },
     "emoji-regex": {
       "version": "8.0.0",
@@ -4254,7 +15739,7 @@
     "encodeurl": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
-      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
+      "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
       "dev": true
     },
     "encoding": {
@@ -4262,47 +15747,57 @@
       "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
       "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
       "dev": true,
+      "optional": true,
       "requires": {
         "iconv-lite": "^0.6.2"
-      }
-    },
-    "end-of-stream": {
-      "version": "1.4.4",
-      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
-      "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
-      "dev": true,
-      "requires": {
-        "once": "^1.4.0"
+      },
+      "dependencies": {
+        "iconv-lite": {
+          "version": "0.6.3",
+          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+          "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "safer-buffer": ">= 2.1.2 < 3.0.0"
+          }
+        }
       }
     },
     "enhanced-resolve": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz",
-      "integrity": "sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==",
+      "version": "5.12.0",
+      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz",
+      "integrity": "sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==",
       "dev": true,
       "requires": {
-        "graceful-fs": "^4.1.2",
-        "memory-fs": "^0.5.0",
-        "tapable": "^1.0.0"
+        "graceful-fs": "^4.2.4",
+        "tapable": "^2.2.0"
       }
     },
     "entities": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz",
-      "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==",
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+      "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
+      "dev": true
+    },
+    "env-paths": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz",
+      "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==",
       "dev": true
     },
     "err-code": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz",
-      "integrity": "sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA=",
+      "integrity": "sha512-CJAN+O0/yA1CKfRn9SXOGctSpEM7DCon/r/5r2eXFMY2zCCJBasFhcM5I+1kh3Ap11FsQCX+vGHceNPvpWKhoA==",
       "dev": true
     },
     "errno": {
-      "version": "0.1.7",
-      "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
-      "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",
+      "version": "0.1.8",
+      "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
+      "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
       "dev": true,
+      "optional": true,
       "requires": {
         "prr": "~1.0.1"
       }
@@ -4316,93 +15811,58 @@
         "is-arrayish": "^0.2.1"
       }
     },
-    "es-abstract": {
-      "version": "1.17.7",
-      "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz",
-      "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==",
-      "dev": true,
-      "requires": {
-        "es-to-primitive": "^1.2.1",
-        "function-bind": "^1.1.1",
-        "has": "^1.0.3",
-        "has-symbols": "^1.0.1",
-        "is-callable": "^1.2.2",
-        "is-regex": "^1.1.1",
-        "object-inspect": "^1.8.0",
-        "object-keys": "^1.1.1",
-        "object.assign": "^4.1.1",
-        "string.prototype.trimend": "^1.0.1",
-        "string.prototype.trimstart": "^1.0.1"
-      }
-    },
-    "es-to-primitive": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
-      "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
-      "dev": true,
-      "requires": {
-        "is-callable": "^1.1.4",
-        "is-date-object": "^1.0.1",
-        "is-symbol": "^1.0.2"
-      }
-    },
-    "es5-ext": {
-      "version": "0.10.53",
-      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz",
-      "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==",
-      "dev": true,
-      "requires": {
-        "es6-iterator": "~2.0.3",
-        "es6-symbol": "~3.1.3",
-        "next-tick": "~1.0.0"
-      }
-    },
-    "es6-iterator": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
-      "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
-      "dev": true,
-      "requires": {
-        "d": "1",
-        "es5-ext": "^0.10.35",
-        "es6-symbol": "^3.1.1"
-      }
-    },
-    "es6-promise": {
-      "version": "4.2.8",
-      "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
-      "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==",
+    "es-module-lexer": {
+      "version": "0.9.3",
+      "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz",
+      "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==",
       "dev": true
     },
-    "es6-promisify": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
-      "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
+    "esbuild": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.8.tgz",
+      "integrity": "sha512-g24ybC3fWhZddZK6R3uD2iF/RIPnRpwJAqLov6ouX3hMbY4+tKolP0VMF3zuIYCaXun+yHwS5IPQ91N2BT191g==",
       "dev": true,
+      "optional": true,
       "requires": {
-        "es6-promise": "^4.0.3"
+        "@esbuild/android-arm": "0.17.8",
+        "@esbuild/android-arm64": "0.17.8",
+        "@esbuild/android-x64": "0.17.8",
+        "@esbuild/darwin-arm64": "0.17.8",
+        "@esbuild/darwin-x64": "0.17.8",
+        "@esbuild/freebsd-arm64": "0.17.8",
+        "@esbuild/freebsd-x64": "0.17.8",
+        "@esbuild/linux-arm": "0.17.8",
+        "@esbuild/linux-arm64": "0.17.8",
+        "@esbuild/linux-ia32": "0.17.8",
+        "@esbuild/linux-loong64": "0.17.8",
+        "@esbuild/linux-mips64el": "0.17.8",
+        "@esbuild/linux-ppc64": "0.17.8",
+        "@esbuild/linux-riscv64": "0.17.8",
+        "@esbuild/linux-s390x": "0.17.8",
+        "@esbuild/linux-x64": "0.17.8",
+        "@esbuild/netbsd-x64": "0.17.8",
+        "@esbuild/openbsd-x64": "0.17.8",
+        "@esbuild/sunos-x64": "0.17.8",
+        "@esbuild/win32-arm64": "0.17.8",
+        "@esbuild/win32-ia32": "0.17.8",
+        "@esbuild/win32-x64": "0.17.8"
       }
     },
-    "es6-symbol": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
-      "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
-      "dev": true,
-      "requires": {
-        "d": "^1.0.1",
-        "ext": "^1.1.2"
-      }
+    "esbuild-wasm": {
+      "version": "0.17.8",
+      "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.17.8.tgz",
+      "integrity": "sha512-zCmpxv95E0FuCmvdw1K836UHnj4EdiQnFfjTby35y3LAjRPtXMj3sbHDRHjbD8Mqg5lTwq3knacr/1qIFU51CQ==",
+      "dev": true
     },
     "escalade": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
-      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
-      "dev": true
+      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
     },
     "escape-html": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
-      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
+      "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
       "dev": true
     },
     "escape-string-regexp": {
@@ -4411,12 +15871,12 @@
       "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
     },
     "eslint-scope": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz",
-      "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==",
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
+      "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
       "dev": true,
       "requires": {
-        "esrecurse": "^4.1.0",
+        "esrecurse": "^4.3.0",
         "estraverse": "^4.1.1"
       }
     },
@@ -4436,9 +15896,9 @@
       },
       "dependencies": {
         "estraverse": {
-          "version": "5.2.0",
-          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
-          "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
+          "version": "5.3.0",
+          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+          "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
           "dev": true
         }
       }
@@ -4458,7 +15918,13 @@
     "etag": {
       "version": "1.8.1",
       "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
-      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
+      "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
+      "dev": true
+    },
+    "eventemitter-asyncresource": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/eventemitter-asyncresource/-/eventemitter-asyncresource-1.0.0.tgz",
+      "integrity": "sha512-39F7TBIV0G7gTelxwbEqnwhp90eqCPON1k0NwNfwhgKn4Co4ybUbj2pECcXT0B3ztRKZ7Pw1JujUUgmQJHcVAQ==",
       "dev": true
     },
     "eventemitter3": {
@@ -4468,128 +15934,62 @@
       "dev": true
     },
     "events": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/events/-/events-3.2.0.tgz",
-      "integrity": "sha512-/46HWwbfCX2xTawVfkKLGxMifJYQBWMwY1mjywRtb4c9x8l5NP3KoJtnIOiL1hfdRkIuYhETxQlo62IF8tcnlg==",
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+      "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
       "dev": true
     },
-    "eventsource": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.1.tgz",
-      "integrity": "sha512-qV5ZC0h7jYIAOhArFJgSfdyz6rALJyb270714o7ZtNnw2WSJ+eexhKtE0O8LYPRsHZHf2osHKZBxGPvm3kPkCA==",
-      "dev": true,
-      "requires": {
-        "original": "^1.0.0"
-      }
-    },
-    "evp_bytestokey": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
-      "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
-      "dev": true,
-      "requires": {
-        "md5.js": "^1.3.4",
-        "safe-buffer": "^5.1.1"
-      }
-    },
     "execa": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz",
-      "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==",
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
+      "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
       "dev": true,
       "requires": {
-        "cross-spawn": "^6.0.0",
-        "get-stream": "^4.0.0",
-        "is-stream": "^1.1.0",
-        "npm-run-path": "^2.0.0",
-        "p-finally": "^1.0.0",
-        "signal-exit": "^3.0.0",
-        "strip-eof": "^1.0.0"
-      }
-    },
-    "expand-brackets": {
-      "version": "2.1.4",
-      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
-      "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
-      "dev": true,
-      "requires": {
-        "debug": "^2.3.3",
-        "define-property": "^0.2.5",
-        "extend-shallow": "^2.0.1",
-        "posix-character-classes": "^0.1.0",
-        "regex-not": "^1.0.0",
-        "snapdragon": "^0.8.1",
-        "to-regex": "^3.0.1"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "2.6.9",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-          "dev": true,
-          "requires": {
-            "ms": "2.0.0"
-          }
-        },
-        "define-property": {
-          "version": "0.2.5",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^0.1.0"
-          }
-        },
-        "extend-shallow": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-          "dev": true,
-          "requires": {
-            "is-extendable": "^0.1.0"
-          }
-        },
-        "ms": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
-          "dev": true
-        }
+        "cross-spawn": "^7.0.3",
+        "get-stream": "^6.0.0",
+        "human-signals": "^2.1.0",
+        "is-stream": "^2.0.0",
+        "merge-stream": "^2.0.0",
+        "npm-run-path": "^4.0.1",
+        "onetime": "^5.1.2",
+        "signal-exit": "^3.0.3",
+        "strip-final-newline": "^2.0.0"
       }
     },
     "express": {
-      "version": "4.17.1",
-      "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
-      "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
+      "version": "4.18.2",
+      "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
+      "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
       "dev": true,
       "requires": {
-        "accepts": "~1.3.7",
+        "accepts": "~1.3.8",
         "array-flatten": "1.1.1",
-        "body-parser": "1.19.0",
-        "content-disposition": "0.5.3",
+        "body-parser": "1.20.1",
+        "content-disposition": "0.5.4",
         "content-type": "~1.0.4",
-        "cookie": "0.4.0",
+        "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.5",
-        "qs": "6.7.0",
+        "proxy-addr": "~2.0.7",
+        "qs": "6.11.0",
         "range-parser": "~1.2.1",
-        "safe-buffer": "5.1.2",
-        "send": "0.17.1",
-        "serve-static": "1.14.1",
-        "setprototypeof": "1.1.1",
-        "statuses": "~1.5.0",
+        "safe-buffer": "5.2.1",
+        "send": "0.18.0",
+        "serve-static": "1.15.0",
+        "setprototypeof": "1.2.0",
+        "statuses": "2.0.1",
         "type-is": "~1.6.18",
         "utils-merge": "1.0.1",
         "vary": "~1.1.2"
@@ -4598,7 +15998,7 @@
         "array-flatten": {
           "version": "1.1.1",
           "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
-          "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
+          "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
           "dev": true
         },
         "debug": {
@@ -4610,27 +16010,22 @@
             "ms": "2.0.0"
           }
         },
+        "depd": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+          "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+          "dev": true
+        },
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
           "dev": true
-        }
-      }
-    },
-    "ext": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz",
-      "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==",
-      "dev": true,
-      "requires": {
-        "type": "^2.0.0"
-      },
-      "dependencies": {
-        "type": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz",
-          "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==",
+        },
+        "safe-buffer": {
+          "version": "5.2.1",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+          "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
           "dev": true
         }
       }
@@ -4641,27 +16036,6 @@
       "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
       "dev": true
     },
-    "extend-shallow": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
-      "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
-      "dev": true,
-      "requires": {
-        "assign-symbols": "^1.0.0",
-        "is-extendable": "^1.0.1"
-      },
-      "dependencies": {
-        "is-extendable": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
-          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
-          "dev": true,
-          "requires": {
-            "is-plain-object": "^2.0.4"
-          }
-        }
-      }
-    },
     "external-editor": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
@@ -4671,82 +16045,6 @@
         "chardet": "^0.7.0",
         "iconv-lite": "^0.4.24",
         "tmp": "^0.0.33"
-      },
-      "dependencies": {
-        "iconv-lite": {
-          "version": "0.4.24",
-          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
-          "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
-          "dev": true,
-          "requires": {
-            "safer-buffer": ">= 2.1.2 < 3"
-          }
-        }
-      }
-    },
-    "extglob": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
-      "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
-      "dev": true,
-      "requires": {
-        "array-unique": "^0.3.2",
-        "define-property": "^1.0.0",
-        "expand-brackets": "^2.1.4",
-        "extend-shallow": "^2.0.1",
-        "fragment-cache": "^0.2.1",
-        "regex-not": "^1.0.0",
-        "snapdragon": "^0.8.1",
-        "to-regex": "^3.0.1"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
-          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^1.0.0"
-          }
-        },
-        "extend-shallow": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-          "dev": true,
-          "requires": {
-            "is-extendable": "^0.1.0"
-          }
-        },
-        "is-accessor-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
-          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-data-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
-          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-descriptor": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
-          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
-          "dev": true,
-          "requires": {
-            "is-accessor-descriptor": "^1.0.0",
-            "is-data-descriptor": "^1.0.0",
-            "kind-of": "^6.0.2"
-          }
-        }
       }
     },
     "extsprintf": {
@@ -4762,17 +16060,16 @@
       "dev": true
     },
     "fast-glob": {
-      "version": "3.2.4",
-      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz",
-      "integrity": "sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ==",
+      "version": "3.2.12",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
+      "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==",
       "dev": true,
       "requires": {
         "@nodelib/fs.stat": "^2.0.2",
         "@nodelib/fs.walk": "^1.2.3",
-        "glob-parent": "^5.1.0",
+        "glob-parent": "^5.1.2",
         "merge2": "^1.3.0",
-        "micromatch": "^4.0.2",
-        "picomatch": "^2.2.1"
+        "micromatch": "^4.0.4"
       }
     },
     "fast-json-stable-stringify": {
@@ -4788,29 +16085,23 @@
       "dev": true
     },
     "fastq": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.9.0.tgz",
-      "integrity": "sha512-i7FVWL8HhVY+CTkwFxkN2mk3h+787ixS5S63eb78diVRc1MCssarHq3W5cj0av7YDSwmaV928RNag+U1etRQ7w==",
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
+      "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
       "dev": true,
       "requires": {
         "reusify": "^1.0.4"
       }
     },
     "faye-websocket": {
-      "version": "0.10.0",
-      "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",
-      "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=",
+      "version": "0.11.4",
+      "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz",
+      "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==",
       "dev": true,
       "requires": {
         "websocket-driver": ">=0.5.1"
       }
     },
-    "figgy-pudding": {
-      "version": "3.5.2",
-      "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz",
-      "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==",
-      "dev": true
-    },
     "figures": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz",
@@ -4820,43 +16111,26 @@
         "escape-string-regexp": "^1.0.5"
       }
     },
-    "file-loader": {
-      "version": "6.0.0",
-      "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.0.0.tgz",
-      "integrity": "sha512-/aMOAYEFXDdjG0wytpTL5YQLfZnnTmLNjn+AIrJ/6HVnTfDqLsVKUUwkDf4I4kgex36BvjuXEn/TX9B/1ESyqQ==",
-      "dev": true,
-      "requires": {
-        "loader-utils": "^2.0.0",
-        "schema-utils": "^2.6.5"
-      }
-    },
-    "filesize": {
-      "version": "3.6.1",
-      "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz",
-      "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==",
-      "dev": true
-    },
     "fill-range": {
       "version": "7.0.1",
       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
       "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
-      "dev": true,
       "requires": {
         "to-regex-range": "^5.0.1"
       }
     },
     "finalhandler": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
-      "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
+      "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
       "dev": true,
       "requires": {
         "debug": "2.6.9",
         "encodeurl": "~1.0.2",
         "escape-html": "~1.0.3",
-        "on-finished": "~2.3.0",
+        "on-finished": "2.4.1",
         "parseurl": "~1.3.3",
-        "statuses": "~1.5.0",
+        "statuses": "2.0.1",
         "unpipe": "~1.0.0"
       },
       "dependencies": {
@@ -4872,15 +16146,15 @@
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
           "dev": true
         }
       }
     },
     "find-cache-dir": {
-      "version": "3.3.1",
-      "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz",
-      "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==",
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz",
+      "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==",
       "dev": true,
       "requires": {
         "commondir": "^1.0.1",
@@ -4897,15 +16171,6 @@
             "semver": "^6.0.0"
           }
         },
-        "pkg-dir": {
-          "version": "4.2.0",
-          "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
-          "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
-          "dev": true,
-          "requires": {
-            "find-up": "^4.0.0"
-          }
-        },
         "semver": {
           "version": "6.3.0",
           "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@@ -4918,31 +16183,16 @@
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
       "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
+      "dev": true,
       "requires": {
         "locate-path": "^5.0.0",
         "path-exists": "^4.0.0"
       }
     },
-    "flush-write-stream": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
-      "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.3",
-        "readable-stream": "^2.3.6"
-      }
-    },
     "follow-redirects": {
-      "version": "1.14.9",
-      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz",
-      "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==",
-      "dev": true
-    },
-    "for-in": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
-      "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
+      "version": "1.15.2",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
+      "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
       "dev": true
     },
     "forever-agent": {
@@ -4963,41 +16213,27 @@
       }
     },
     "forwarded": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
-      "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+      "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
       "dev": true
     },
-    "fragment-cache": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
-      "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
-      "dev": true,
-      "requires": {
-        "map-cache": "^0.2.2"
-      }
+    "fraction.js": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
+      "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==",
+      "dev": true
     },
     "fresh": {
       "version": "0.5.2",
       "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
-      "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
+      "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
       "dev": true
     },
-    "from2": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
-      "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.1",
-        "readable-stream": "^2.0.0"
-      }
-    },
     "fs-extra": {
       "version": "4.0.2",
       "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz",
-      "integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=",
-      "dev": true,
+      "integrity": "sha512-wYid1zXctNLgas1pZ8q8ChdsnGg4DHZVqMzJ7pOE85q5BppAEXgQGSoOjVgrcw5yI7pzz49p9AfMhM7z5PRuaw==",
       "requires": {
         "graceful-fs": "^4.1.2",
         "jsonfile": "^4.0.0",
@@ -5013,17 +16249,11 @@
         "minipass": "^3.0.0"
       }
     },
-    "fs-write-stream-atomic": {
-      "version": "1.0.10",
-      "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz",
-      "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.2",
-        "iferr": "^0.1.5",
-        "imurmurhash": "^0.1.4",
-        "readable-stream": "1 || 2"
-      }
+    "fs-monkey": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz",
+      "integrity": "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q==",
+      "dev": true
     },
     "fs.realpath": {
       "version": "1.0.0",
@@ -5031,10 +16261,9 @@
       "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
     },
     "fsevents": {
-      "version": "2.1.3",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
-      "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
-      "dev": true,
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
       "optional": true
     },
     "function-bind": {
@@ -5042,11 +16271,58 @@
       "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
       "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
     },
-    "genfun": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz",
-      "integrity": "sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA==",
-      "dev": true
+    "gauge": {
+      "version": "2.7.4",
+      "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+      "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==",
+      "dev": true,
+      "requires": {
+        "aproba": "^1.0.3",
+        "console-control-strings": "^1.0.0",
+        "has-unicode": "^2.0.0",
+        "object-assign": "^4.1.0",
+        "signal-exit": "^3.0.0",
+        "string-width": "^1.0.1",
+        "strip-ansi": "^3.0.1",
+        "wide-align": "^1.1.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+          "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
+          "dev": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+          "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==",
+          "dev": true,
+          "requires": {
+            "number-is-nan": "^1.0.0"
+          }
+        },
+        "string-width": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+          "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+          "dev": true,
+          "requires": {
+            "code-point-at": "^1.0.0",
+            "is-fullwidth-code-point": "^1.0.0",
+            "strip-ansi": "^3.0.0"
+          }
+        },
+        "strip-ansi": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+          "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+          "dev": true,
+          "requires": {
+            "ansi-regex": "^2.0.0"
+          }
+        }
+      }
     },
     "gensync": {
       "version": "1.0.0-beta.2",
@@ -5059,29 +16335,26 @@
       "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
     },
     "get-intrinsic": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz",
-      "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.0.tgz",
+      "integrity": "sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==",
       "dev": true,
       "requires": {
         "function-bind": "^1.1.1",
         "has": "^1.0.3",
-        "has-symbols": "^1.0.1"
+        "has-symbols": "^1.0.3"
       }
     },
+    "get-package-type": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz",
+      "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==",
+      "dev": true
+    },
     "get-stream": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
-      "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
-      "dev": true,
-      "requires": {
-        "pump": "^3.0.0"
-      }
-    },
-    "get-value": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
-      "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+      "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
       "dev": true
     },
     "getpass": {
@@ -5107,38 +16380,41 @@
       }
     },
     "glob-parent": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
-      "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
-      "dev": true,
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
       "requires": {
         "is-glob": "^4.0.1"
       }
     },
+    "glob-to-regexp": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
+      "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
+      "dev": true
+    },
     "globals": {
       "version": "11.12.0",
       "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz",
       "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
     },
     "globby": {
-      "version": "11.0.1",
-      "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.1.tgz",
-      "integrity": "sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ==",
+      "version": "13.1.3",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz",
+      "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==",
       "dev": true,
       "requires": {
-        "array-union": "^2.1.0",
         "dir-glob": "^3.0.1",
-        "fast-glob": "^3.1.1",
-        "ignore": "^5.1.4",
-        "merge2": "^1.3.0",
-        "slash": "^3.0.0"
+        "fast-glob": "^3.2.11",
+        "ignore": "^5.2.0",
+        "merge2": "^1.4.1",
+        "slash": "^4.0.0"
       }
     },
     "graceful-fs": {
-      "version": "4.2.4",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
-      "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==",
-      "dev": true
+      "version": "4.2.10",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
+      "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
     },
     "guacamole-common-js": {
       "version": "1.2.0",
@@ -5146,13 +16422,12 @@
       "integrity": "sha512-QshVHQq3t4KAdf6PpOEBZNLwl+uMA9e8jNfTrudxpmxZPPJ+1b7QiYbVV1t9cZrmvDLy4I/tga+xHkWgNaEerw=="
     },
     "gzip-size": {
-      "version": "5.1.1",
-      "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz",
-      "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==",
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz",
+      "integrity": "sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==",
       "dev": true,
       "requires": {
-        "duplexer": "^0.1.1",
-        "pify": "^4.0.1"
+        "duplexer": "^0.1.2"
       }
     },
     "handle-thing": {
@@ -5191,124 +16466,32 @@
       "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
     },
     "has-symbols": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
-      "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+      "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
       "dev": true
     },
-    "has-value": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
-      "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
-      "dev": true,
-      "requires": {
-        "get-value": "^2.0.6",
-        "has-values": "^1.0.0",
-        "isobject": "^3.0.0"
-      }
-    },
-    "has-values": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
-      "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
-      "dev": true,
-      "requires": {
-        "is-number": "^3.0.0",
-        "kind-of": "^4.0.0"
-      },
-      "dependencies": {
-        "is-number": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
-          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
-          "dev": true,
-          "requires": {
-            "kind-of": "^3.0.2"
-          },
-          "dependencies": {
-            "kind-of": {
-              "version": "3.2.2",
-              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-              "dev": true,
-              "requires": {
-                "is-buffer": "^1.1.5"
-              }
-            }
-          }
-        },
-        "kind-of": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
-          "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
-          "dev": true,
-          "requires": {
-            "is-buffer": "^1.1.5"
-          }
-        }
-      }
-    },
-    "hash-base": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
-      "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.4",
-        "readable-stream": "^3.6.0",
-        "safe-buffer": "^5.2.0"
-      },
-      "dependencies": {
-        "readable-stream": {
-          "version": "3.6.0",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
-          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
-          "dev": true,
-          "requires": {
-            "inherits": "^2.0.3",
-            "string_decoder": "^1.1.1",
-            "util-deprecate": "^1.0.1"
-          }
-        },
-        "safe-buffer": {
-          "version": "5.2.1",
-          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-          "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
-          "dev": true
-        }
-      }
-    },
-    "hash.js": {
-      "version": "1.1.7",
-      "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
-      "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.3",
-        "minimalistic-assert": "^1.0.1"
-      }
-    },
-    "hex-color-regex": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
-      "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==",
+    "has-unicode": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+      "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==",
       "dev": true
     },
-    "hmac-drbg": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
-      "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
+    "hdr-histogram-js": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz",
+      "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==",
       "dev": true,
       "requires": {
-        "hash.js": "^1.0.3",
-        "minimalistic-assert": "^1.0.0",
-        "minimalistic-crypto-utils": "^1.0.1"
+        "@assemblyscript/loader": "^0.10.1",
+        "base64-js": "^1.2.0",
+        "pako": "^1.0.3"
       }
     },
-    "hoopy": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
-      "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==",
+    "hdr-histogram-percentiles-obj": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz",
+      "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==",
       "dev": true
     },
     "hosted-git-info": {
@@ -5323,7 +16506,7 @@
     "hpack.js": {
       "version": "2.1.6",
       "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz",
-      "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=",
+      "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==",
       "dev": true,
       "requires": {
         "inherits": "^2.0.1",
@@ -5332,63 +16515,51 @@
         "wbuf": "^1.1.0"
       }
     },
-    "hsl-regex": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz",
-      "integrity": "sha1-1JMwx4ntgZ4nakwNJy3/owsY/m4=",
-      "dev": true
-    },
-    "hsla-regex": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz",
-      "integrity": "sha1-wc56MWjIxmFAM6S194d/OyJfnDg=",
-      "dev": true
-    },
-    "html-comment-regex": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz",
-      "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==",
-      "dev": true
-    },
     "html-entities": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.3.1.tgz",
-      "integrity": "sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA==",
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz",
+      "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==",
       "dev": true
     },
     "http-cache-semantics": {
-      "version": "3.8.1",
-      "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz",
-      "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==",
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz",
+      "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==",
       "dev": true
     },
     "http-deceiver": {
       "version": "1.2.7",
       "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
-      "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=",
+      "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==",
       "dev": true
     },
     "http-errors": {
-      "version": "1.7.2",
-      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
-      "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
+      "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
       "dev": true,
       "requires": {
-        "depd": "~1.1.2",
-        "inherits": "2.0.3",
-        "setprototypeof": "1.1.1",
-        "statuses": ">= 1.5.0 < 2",
-        "toidentifier": "1.0.0"
+        "depd": "2.0.0",
+        "inherits": "2.0.4",
+        "setprototypeof": "1.2.0",
+        "statuses": "2.0.1",
+        "toidentifier": "1.0.1"
       },
       "dependencies": {
-        "inherits": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+        "depd": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+          "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
           "dev": true
         }
       }
     },
+    "http-parser-js": {
+      "version": "0.5.8",
+      "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz",
+      "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==",
+      "dev": true
+    },
     "http-proxy": {
       "version": "1.18.1",
       "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
@@ -5401,147 +16572,27 @@
       }
     },
     "http-proxy-agent": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
-      "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz",
+      "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==",
       "dev": true,
       "requires": {
-        "agent-base": "4",
-        "debug": "3.1.0"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
-          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
-          "dev": true,
-          "requires": {
-            "ms": "2.0.0"
-          }
-        },
-        "ms": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
-          "dev": true
-        }
+        "@tootallnate/once": "1",
+        "agent-base": "6",
+        "debug": "4"
       }
     },
     "http-proxy-middleware": {
-      "version": "0.19.1",
-      "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz",
-      "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==",
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz",
+      "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==",
       "dev": true,
       "requires": {
-        "http-proxy": "^1.17.0",
-        "is-glob": "^4.0.0",
-        "lodash": "^4.17.11",
-        "micromatch": "^3.1.10"
-      },
-      "dependencies": {
-        "braces": {
-          "version": "2.3.2",
-          "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
-          "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
-          "dev": true,
-          "requires": {
-            "arr-flatten": "^1.1.0",
-            "array-unique": "^0.3.2",
-            "extend-shallow": "^2.0.1",
-            "fill-range": "^4.0.0",
-            "isobject": "^3.0.1",
-            "repeat-element": "^1.1.2",
-            "snapdragon": "^0.8.1",
-            "snapdragon-node": "^2.0.1",
-            "split-string": "^3.0.2",
-            "to-regex": "^3.0.1"
-          },
-          "dependencies": {
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            }
-          }
-        },
-        "fill-range": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
-          "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
-          "dev": true,
-          "requires": {
-            "extend-shallow": "^2.0.1",
-            "is-number": "^3.0.0",
-            "repeat-string": "^1.6.1",
-            "to-regex-range": "^2.1.0"
-          },
-          "dependencies": {
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            }
-          }
-        },
-        "is-number": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
-          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
-          "dev": true,
-          "requires": {
-            "kind-of": "^3.0.2"
-          },
-          "dependencies": {
-            "kind-of": {
-              "version": "3.2.2",
-              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-              "dev": true,
-              "requires": {
-                "is-buffer": "^1.1.5"
-              }
-            }
-          }
-        },
-        "micromatch": {
-          "version": "3.1.10",
-          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
-          "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
-          "dev": true,
-          "requires": {
-            "arr-diff": "^4.0.0",
-            "array-unique": "^0.3.2",
-            "braces": "^2.3.1",
-            "define-property": "^2.0.2",
-            "extend-shallow": "^3.0.2",
-            "extglob": "^2.0.4",
-            "fragment-cache": "^0.2.1",
-            "kind-of": "^6.0.2",
-            "nanomatch": "^1.2.9",
-            "object.pick": "^1.3.0",
-            "regex-not": "^1.0.0",
-            "snapdragon": "^0.8.1",
-            "to-regex": "^3.0.2"
-          }
-        },
-        "to-regex-range": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
-          "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
-          "dev": true,
-          "requires": {
-            "is-number": "^3.0.0",
-            "repeat-string": "^1.6.1"
-          }
-        }
+        "@types/http-proxy": "^1.17.8",
+        "http-proxy": "^1.18.1",
+        "is-glob": "^4.0.1",
+        "is-plain-obj": "^3.0.0",
+        "micromatch": "^4.0.2"
       }
     },
     "http-signature": {
@@ -5555,59 +16606,46 @@
         "sshpk": "^1.7.0"
       }
     },
-    "https-browserify": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
-      "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
-      "dev": true
-    },
     "https-proxy-agent": {
-      "version": "2.2.4",
-      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
-      "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
+      "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==",
       "dev": true,
       "requires": {
-        "agent-base": "^4.3.0",
-        "debug": "^3.1.0"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "3.2.6",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
-          "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        }
+        "agent-base": "6",
+        "debug": "4"
       }
     },
+    "human-signals": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
+      "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
+      "dev": true
+    },
     "humanize-ms": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
-      "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=",
+      "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
       "dev": true,
       "requires": {
         "ms": "^2.0.0"
       }
     },
     "iconv-lite": {
-      "version": "0.6.2",
-      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz",
-      "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==",
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
       "dev": true,
       "requires": {
-        "safer-buffer": ">= 2.1.2 < 3.0.0"
+        "safer-buffer": ">= 2.1.2 < 3"
       }
     },
     "icss-utils": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz",
-      "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==",
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz",
+      "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==",
       "dev": true,
-      "requires": {
-        "postcss": "^7.0.14"
-      }
+      "requires": {}
     },
     "ieee754": {
       "version": "1.2.1",
@@ -5615,22 +16653,16 @@
       "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
       "dev": true
     },
-    "iferr": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz",
-      "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=",
-      "dev": true
-    },
     "ignore": {
-      "version": "5.1.8",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
-      "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
+      "version": "5.2.4",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
+      "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
       "dev": true
     },
     "ignore-walk": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz",
-      "integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==",
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz",
+      "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==",
       "dev": true,
       "requires": {
         "minimatch": "^3.0.4"
@@ -5639,46 +16671,32 @@
     "image-size": {
       "version": "0.5.5",
       "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz",
-      "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=",
+      "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==",
       "dev": true,
       "optional": true
     },
-    "import-cwd": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz",
-      "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=",
-      "dev": true,
-      "requires": {
-        "import-from": "^2.1.0"
-      }
+    "immutable": {
+      "version": "4.2.4",
+      "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.4.tgz",
+      "integrity": "sha512-WDxL3Hheb1JkRN3sQkyujNlL/xRjAo3rJtaU5xeufUauG66JdMr32bLj4gF+vWl84DIA3Zxw7tiAjneYzRRw+w==",
+      "dev": true
     },
     "import-fresh": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz",
-      "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=",
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
       "dev": true,
       "requires": {
-        "caller-path": "^2.0.0",
-        "resolve-from": "^3.0.0"
-      }
-    },
-    "import-from": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz",
-      "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=",
-      "dev": true,
-      "requires": {
-        "resolve-from": "^3.0.0"
-      }
-    },
-    "import-local": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz",
-      "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==",
-      "dev": true,
-      "requires": {
-        "pkg-dir": "^3.0.0",
-        "resolve-cwd": "^2.0.0"
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      },
+      "dependencies": {
+        "resolve-from": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+          "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+          "dev": true
+        }
       }
     },
     "imurmurhash": {
@@ -5693,12 +16711,6 @@
       "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
       "dev": true
     },
-    "indexes-of": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
-      "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=",
-      "dev": true
-    },
     "infer-owner": {
       "version": "1.0.4",
       "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz",
@@ -5720,9 +16732,9 @@
       "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
     },
     "ini": {
-      "version": "1.3.5",
-      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
-      "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz",
+      "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==",
       "dev": true
     },
     "inquirer": {
@@ -5797,116 +16809,32 @@
         }
       }
     },
-    "internal-ip": {
-      "version": "4.3.0",
-      "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz",
-      "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==",
-      "dev": true,
-      "requires": {
-        "default-gateway": "^4.2.0",
-        "ipaddr.js": "^1.9.0"
-      }
-    },
-    "invariant": {
-      "version": "2.2.4",
-      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
-      "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
-      "dev": true,
-      "requires": {
-        "loose-envify": "^1.0.0"
-      }
-    },
     "ip": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
-      "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=",
-      "dev": true
-    },
-    "ip-regex": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
-      "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=",
+      "version": "1.1.8",
+      "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz",
+      "integrity": "sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg==",
       "dev": true
     },
     "ipaddr.js": {
-      "version": "1.9.1",
-      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
-      "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
-      "dev": true
-    },
-    "is-absolute-url": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz",
-      "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=",
-      "dev": true
-    },
-    "is-accessor-descriptor": {
-      "version": "0.1.6",
-      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
-      "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
-      "dev": true,
-      "requires": {
-        "kind-of": "^3.0.2"
-      },
-      "dependencies": {
-        "kind-of": {
-          "version": "3.2.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-          "dev": true,
-          "requires": {
-            "is-buffer": "^1.1.5"
-          }
-        }
-      }
-    },
-    "is-arguments": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz",
-      "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz",
+      "integrity": "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng==",
       "dev": true
     },
     "is-arrayish": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
-      "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
+      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==",
       "dev": true
     },
     "is-binary-path": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
       "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
-      "dev": true,
       "requires": {
         "binary-extensions": "^2.0.0"
       }
     },
-    "is-buffer": {
-      "version": "1.1.6",
-      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
-      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
-      "dev": true
-    },
-    "is-callable": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz",
-      "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==",
-      "dev": true
-    },
-    "is-color-stop": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz",
-      "integrity": "sha1-z/9HGu5N1cnhWFmPvhKWe1za00U=",
-      "dev": true,
-      "requires": {
-        "css-color-names": "^0.0.4",
-        "hex-color-regex": "^1.1.0",
-        "hsl-regex": "^1.0.0",
-        "hsla-regex": "^1.0.0",
-        "rgb-regex": "^1.0.1",
-        "rgba-regex": "^1.0.0"
-      }
-    },
     "is-core-module": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz",
@@ -5915,74 +16843,16 @@
         "has": "^1.0.3"
       }
     },
-    "is-data-descriptor": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
-      "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
-      "dev": true,
-      "requires": {
-        "kind-of": "^3.0.2"
-      },
-      "dependencies": {
-        "kind-of": {
-          "version": "3.2.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-          "dev": true,
-          "requires": {
-            "is-buffer": "^1.1.5"
-          }
-        }
-      }
-    },
-    "is-date-object": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz",
-      "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==",
-      "dev": true
-    },
-    "is-descriptor": {
-      "version": "0.1.6",
-      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
-      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
-      "dev": true,
-      "requires": {
-        "is-accessor-descriptor": "^0.1.6",
-        "is-data-descriptor": "^0.1.4",
-        "kind-of": "^5.0.0"
-      },
-      "dependencies": {
-        "kind-of": {
-          "version": "5.1.0",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
-          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
-          "dev": true
-        }
-      }
-    },
-    "is-directory": {
-      "version": "0.3.1",
-      "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz",
-      "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
-      "dev": true
-    },
     "is-docker": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz",
-      "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==",
-      "dev": true
-    },
-    "is-extendable": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
-      "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
+      "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
       "dev": true
     },
     "is-extglob": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
-      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
-      "dev": true
+      "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
     },
     "is-fullwidth-code-point": {
       "version": "3.0.0",
@@ -5990,10 +16860,9 @@
       "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
     },
     "is-glob": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
-      "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
-      "dev": true,
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
       "requires": {
         "is-extglob": "^2.1.1"
       }
@@ -6004,52 +16873,21 @@
       "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==",
       "dev": true
     },
-    "is-negative-zero": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz",
-      "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=",
+    "is-lambda": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz",
+      "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==",
       "dev": true
     },
     "is-number": {
       "version": "7.0.0",
       "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-      "dev": true
-    },
-    "is-obj": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
-      "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
-      "dev": true
-    },
-    "is-path-cwd": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz",
-      "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==",
-      "dev": true
-    },
-    "is-path-in-cwd": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz",
-      "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==",
-      "dev": true,
-      "requires": {
-        "is-path-inside": "^2.1.0"
-      }
-    },
-    "is-path-inside": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz",
-      "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==",
-      "dev": true,
-      "requires": {
-        "path-is-inside": "^1.0.2"
-      }
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
     },
     "is-plain-obj": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
-      "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz",
+      "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==",
       "dev": true
     },
     "is-plain-object": {
@@ -6061,55 +16899,28 @@
         "isobject": "^3.0.1"
       }
     },
-    "is-regex": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz",
-      "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==",
-      "dev": true,
-      "requires": {
-        "has-symbols": "^1.0.1"
-      }
-    },
-    "is-resolvable": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
-      "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==",
-      "dev": true
-    },
     "is-stream": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
-      "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
+      "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
       "dev": true
     },
-    "is-svg": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-3.0.0.tgz",
-      "integrity": "sha512-gi4iHK53LR2ujhLVVj+37Ykh9GLqYHX6JOVXbLAucaG/Cqw9xwdFOjDM2qeifLs1sF1npXXFvDu0r5HNgCMrzQ==",
-      "dev": true,
-      "requires": {
-        "html-comment-regex": "^1.1.0"
-      }
-    },
-    "is-symbol": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
-      "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==",
-      "dev": true,
-      "requires": {
-        "has-symbols": "^1.0.1"
-      }
-    },
     "is-typedarray": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
       "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=",
       "dev": true
     },
-    "is-windows": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
-      "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+    "is-unicode-supported": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz",
+      "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==",
+      "dev": true
+    },
+    "is-what": {
+      "version": "3.14.1",
+      "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz",
+      "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==",
       "dev": true
     },
     "is-wsl": {
@@ -6130,13 +16941,13 @@
     "isexe": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
+      "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
       "dev": true
     },
     "isobject": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
-      "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
+      "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
       "dev": true
     },
     "isstream": {
@@ -6146,20 +16957,21 @@
       "dev": true
     },
     "istanbul-lib-coverage": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz",
-      "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==",
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz",
+      "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==",
       "dev": true
     },
     "istanbul-lib-instrument": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz",
-      "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==",
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz",
+      "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==",
       "dev": true,
       "requires": {
-        "@babel/core": "^7.7.5",
+        "@babel/core": "^7.12.3",
+        "@babel/parser": "^7.14.7",
         "@istanbuljs/schema": "^0.1.2",
-        "istanbul-lib-coverage": "^3.0.0",
+        "istanbul-lib-coverage": "^3.2.0",
         "semver": "^6.3.0"
       },
       "dependencies": {
@@ -6172,14 +16984,14 @@
       }
     },
     "jest-worker": {
-      "version": "26.3.0",
-      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.3.0.tgz",
-      "integrity": "sha512-Vmpn2F6IASefL+DVBhPzI2J9/GJUsqzomdeN+P+dK8/jKxbh8R3BtFnx3FIta7wYlPU62cpJMJQo4kuOowcMnw==",
+      "version": "27.5.1",
+      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
+      "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
       "dev": true,
       "requires": {
         "@types/node": "*",
         "merge-stream": "^2.0.0",
-        "supports-color": "^7.0.0"
+        "supports-color": "^8.0.0"
       },
       "dependencies": {
         "has-flag": {
@@ -6189,9 +17001,9 @@
           "dev": true
         },
         "supports-color": {
-          "version": "7.2.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "version": "8.1.1",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
+          "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
           "dev": true,
           "requires": {
             "has-flag": "^4.0.0"
@@ -6225,12 +17037,6 @@
       "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
       "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
     },
-    "json-parse-better-errors": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz",
-      "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==",
-      "dev": true
-    },
     "json-parse-even-better-errors": {
       "version": "2.3.1",
       "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
@@ -6238,9 +17044,9 @@
       "dev": true
     },
     "json-schema": {
-      "version": "0.2.3",
-      "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
-      "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
+      "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==",
       "dev": true
     },
     "json-schema-traverse": {
@@ -6255,31 +17061,21 @@
       "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=",
       "dev": true
     },
-    "json3": {
-      "version": "3.3.3",
-      "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz",
-      "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==",
-      "dev": true
-    },
     "json5": {
-      "version": "2.1.3",
-      "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz",
-      "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==",
-      "requires": {
-        "minimist": "^1.2.5"
-      }
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
+      "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="
     },
     "jsonc-parser": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.3.0.tgz",
-      "integrity": "sha512-b0EBt8SWFNnixVdvoR2ZtEGa9ZqLhbJnOjezn+WP+8kspFm+PFYDN8Z4Bc7pRlDjvuVcADSUkroIuTWWn/YiIA==",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.0.0.tgz",
+      "integrity": "sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==",
       "dev": true
     },
     "jsonfile": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
-      "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
-      "dev": true,
+      "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
       "requires": {
         "graceful-fs": "^4.1.6"
       }
@@ -6287,18 +17083,18 @@
     "jsonparse": {
       "version": "1.3.1",
       "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
-      "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=",
+      "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==",
       "dev": true
     },
     "jsprim": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
-      "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
+      "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
       "dev": true,
       "requires": {
         "assert-plus": "1.0.0",
         "extsprintf": "1.3.0",
-        "json-schema": "0.2.3",
+        "json-schema": "0.4.0",
         "verror": "1.10.0"
       }
     },
@@ -6311,12 +17107,6 @@
         "source-map-support": "^0.5.5"
       }
     },
-    "killable": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
-      "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==",
-      "dev": true
-    },
     "kind-of": {
       "version": "6.0.3",
       "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
@@ -6324,25 +17114,27 @@
       "dev": true
     },
     "klona": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz",
-      "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==",
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz",
+      "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==",
       "dev": true
     },
     "less": {
-      "version": "3.12.2",
-      "resolved": "https://registry.npmjs.org/less/-/less-3.12.2.tgz",
-      "integrity": "sha512-+1V2PCMFkL+OIj2/HrtrvZw0BC0sYLMICJfbQjuj/K8CEnlrFX6R5cKKgzzttsZDHyxQNL1jqMREjKN3ja/E3Q==",
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/less/-/less-4.1.3.tgz",
+      "integrity": "sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==",
       "dev": true,
       "requires": {
+        "copy-anything": "^2.0.1",
         "errno": "^0.1.1",
         "graceful-fs": "^4.1.2",
         "image-size": "~0.5.0",
         "make-dir": "^2.1.0",
         "mime": "^1.4.1",
-        "native-request": "^1.0.5",
+        "needle": "^3.1.0",
+        "parse-node-version": "^1.0.1",
         "source-map": "~0.6.0",
-        "tslib": "^1.10.0"
+        "tslib": "^2.3.0"
       },
       "dependencies": {
         "source-map": {
@@ -6355,63 +17147,46 @@
       }
     },
     "less-loader": {
-      "version": "6.2.0",
-      "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-6.2.0.tgz",
-      "integrity": "sha512-Cl5h95/Pz/PWub/tCBgT1oNMFeH1WTD33piG80jn5jr12T4XbxZcjThwNXDQ7AG649WEynuIzO4b0+2Tn9Qolg==",
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.0.tgz",
+      "integrity": "sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==",
       "dev": true,
       "requires": {
-        "clone": "^2.1.2",
-        "less": "^3.11.3",
-        "loader-utils": "^2.0.0",
-        "schema-utils": "^2.7.0"
-      }
-    },
-    "leven": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz",
-      "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==",
-      "dev": true
-    },
-    "levenary": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz",
-      "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==",
-      "dev": true,
-      "requires": {
-        "leven": "^3.1.0"
+        "klona": "^2.0.4"
       }
     },
     "license-webpack-plugin": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-2.3.0.tgz",
-      "integrity": "sha512-JK/DXrtN6UeYQSgkg5q1+pgJ8aiKPL9tnz9Wzw+Ikkf+8mJxG56x6t8O+OH/tAeF/5NREnelTEMyFtbJNkjH4w==",
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz",
+      "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==",
       "dev": true,
       "requires": {
-        "@types/webpack-sources": "^0.1.5",
-        "webpack-sources": "^1.2.0"
+        "webpack-sources": "^3.0.0"
       }
     },
+    "lines-and-columns": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+      "dev": true
+    },
     "loader-runner": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz",
-      "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==",
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
+      "integrity": "sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==",
       "dev": true
     },
     "loader-utils": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
-      "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
-      "dev": true,
-      "requires": {
-        "big.js": "^5.2.2",
-        "emojis-list": "^3.0.0",
-        "json5": "^2.1.2"
-      }
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz",
+      "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==",
+      "dev": true
     },
     "locate-path": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
       "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
+      "dev": true,
       "requires": {
         "p-locate": "^4.1.0"
       }
@@ -6421,37 +17196,25 @@
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
       "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
     },
-    "lodash.clonedeep": {
+    "lodash.debounce": {
+      "version": "4.0.8",
+      "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+      "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==",
+      "dev": true
+    },
+    "lodash.isequal": {
       "version": "4.5.0",
-      "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
-      "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
-      "dev": true
-    },
-    "lodash.memoize": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
-      "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
-      "dev": true
-    },
-    "lodash.sortby": {
-      "version": "4.7.0",
-      "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
-      "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=",
-      "dev": true
-    },
-    "lodash.uniq": {
-      "version": "4.5.0",
-      "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
-      "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=",
-      "dev": true
+      "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+      "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
     },
     "log-symbols": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.0.0.tgz",
-      "integrity": "sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA==",
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz",
+      "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==",
       "dev": true,
       "requires": {
-        "chalk": "^4.0.0"
+        "chalk": "^4.1.0",
+        "is-unicode-supported": "^0.1.0"
       },
       "dependencies": {
         "ansi-styles": {
@@ -6464,9 +17227,9 @@
           }
         },
         "chalk": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
-          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
           "dev": true,
           "requires": {
             "ansi-styles": "^4.1.0",
@@ -6505,21 +17268,6 @@
         }
       }
     },
-    "loglevel": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.0.tgz",
-      "integrity": "sha512-i2sY04nal5jDcagM3FMfG++T69GEEM8CYuOfeOIvmXzOIcwE9a/CJPR0MFM97pYMj/u10lzz7/zd7+qwhrBTqQ==",
-      "dev": true
-    },
-    "loose-envify": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
-      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
-      "dev": true,
-      "requires": {
-        "js-tokens": "^3.0.0 || ^4.0.0"
-      }
-    },
     "lru-cache": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
@@ -6533,7 +17281,6 @@
       "version": "0.25.7",
       "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
       "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
-      "dev": true,
       "requires": {
         "sourcemap-codec": "^1.4.4"
       }
@@ -6543,6 +17290,7 @@
       "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz",
       "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==",
       "dev": true,
+      "optional": true,
       "requires": {
         "pify": "^4.0.1",
         "semver": "^5.6.0"
@@ -6555,173 +17303,73 @@
       "dev": true
     },
     "make-fetch-happen": {
-      "version": "5.0.2",
-      "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz",
-      "integrity": "sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag==",
+      "version": "8.0.14",
+      "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-8.0.14.tgz",
+      "integrity": "sha512-EsS89h6l4vbfJEtBZnENTOFk8mCRpY5ru36Xe5bcX1KYIli2mkSHqoFsp5O1wMDvTJJzxe/4THpCTtygjeeGWQ==",
       "dev": true,
       "requires": {
-        "agentkeepalive": "^3.4.1",
-        "cacache": "^12.0.0",
-        "http-cache-semantics": "^3.8.1",
-        "http-proxy-agent": "^2.1.0",
-        "https-proxy-agent": "^2.2.3",
-        "lru-cache": "^5.1.1",
-        "mississippi": "^3.0.0",
-        "node-fetch-npm": "^2.0.2",
-        "promise-retry": "^1.1.1",
-        "socks-proxy-agent": "^4.0.0",
-        "ssri": "^6.0.0"
+        "agentkeepalive": "^4.1.3",
+        "cacache": "^15.0.5",
+        "http-cache-semantics": "^4.1.0",
+        "http-proxy-agent": "^4.0.1",
+        "https-proxy-agent": "^5.0.0",
+        "is-lambda": "^1.0.1",
+        "lru-cache": "^6.0.0",
+        "minipass": "^3.1.3",
+        "minipass-collect": "^1.0.2",
+        "minipass-fetch": "^1.3.2",
+        "minipass-flush": "^1.0.5",
+        "minipass-pipeline": "^1.2.4",
+        "promise-retry": "^2.0.1",
+        "socks-proxy-agent": "^5.0.0",
+        "ssri": "^8.0.0"
       },
       "dependencies": {
-        "cacache": {
-          "version": "12.0.4",
-          "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz",
-          "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==",
-          "dev": true,
-          "requires": {
-            "bluebird": "^3.5.5",
-            "chownr": "^1.1.1",
-            "figgy-pudding": "^3.5.1",
-            "glob": "^7.1.4",
-            "graceful-fs": "^4.1.15",
-            "infer-owner": "^1.0.3",
-            "lru-cache": "^5.1.1",
-            "mississippi": "^3.0.0",
-            "mkdirp": "^0.5.1",
-            "move-concurrently": "^1.0.1",
-            "promise-inflight": "^1.0.1",
-            "rimraf": "^2.6.3",
-            "ssri": "^6.0.1",
-            "unique-filename": "^1.1.1",
-            "y18n": "^4.0.0"
-          }
-        },
-        "chownr": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
-          "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
+        "err-code": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz",
+          "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==",
           "dev": true
         },
-        "glob": {
-          "version": "7.1.6",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
+        "promise-retry": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz",
+          "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==",
           "dev": true,
           "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
+            "err-code": "^2.0.2",
+            "retry": "^0.12.0"
           }
         },
-        "lru-cache": {
-          "version": "5.1.1",
-          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
-          "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
-          "dev": true,
-          "requires": {
-            "yallist": "^3.0.2"
-          }
-        },
-        "rimraf": {
-          "version": "2.7.1",
-          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
-          "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
-          "dev": true,
-          "requires": {
-            "glob": "^7.1.3"
-          }
-        },
-        "ssri": {
-          "version": "6.0.2",
-          "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz",
-          "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==",
-          "dev": true,
-          "requires": {
-            "figgy-pudding": "^3.5.1"
-          }
-        },
-        "yallist": {
-          "version": "3.1.1",
-          "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
-          "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+        "retry": {
+          "version": "0.12.0",
+          "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
+          "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=",
           "dev": true
         }
       }
     },
-    "map-cache": {
-      "version": "0.2.2",
-      "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
-      "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
-      "dev": true
-    },
-    "map-visit": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
-      "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
-      "dev": true,
-      "requires": {
-        "object-visit": "^1.0.0"
-      }
-    },
-    "md5.js": {
-      "version": "1.3.5",
-      "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
-      "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
-      "dev": true,
-      "requires": {
-        "hash-base": "^3.0.0",
-        "inherits": "^2.0.1",
-        "safe-buffer": "^5.1.2"
-      }
-    },
-    "mdn-data": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.4.tgz",
-      "integrity": "sha512-iV3XNKw06j5Q7mi6h+9vbx23Tv7JkjEVgKHW4pimwyDGWm0OIQntJJ+u1C6mg6mK1EaTv42XQ7w76yuzH7M2cA==",
-      "dev": true
-    },
     "media-typer": {
       "version": "0.3.0",
       "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
-      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
+      "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
       "dev": true
     },
-    "memory-fs": {
-      "version": "0.5.0",
-      "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz",
-      "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==",
+    "memfs": {
+      "version": "3.4.13",
+      "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.13.tgz",
+      "integrity": "sha512-omTM41g3Skpvx5dSYeZIbXKcXoAVc/AoMNwn9TKx++L/gaen/+4TTttmu8ZSch5vfVJ8uJvGbroTsIlslRg6lg==",
       "dev": true,
       "requires": {
-        "errno": "^0.1.3",
-        "readable-stream": "^2.0.1"
+        "fs-monkey": "^1.0.3"
       }
     },
     "merge-descriptors": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
-      "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
+      "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==",
       "dev": true
     },
-    "merge-source-map": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz",
-      "integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==",
-      "dev": true,
-      "requires": {
-        "source-map": "^0.6.1"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
-      }
-    },
     "merge-stream": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
@@ -6737,35 +17385,17 @@
     "methods": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
-      "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
+      "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
       "dev": true
     },
     "micromatch": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz",
-      "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==",
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+      "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
       "dev": true,
       "requires": {
-        "braces": "^3.0.1",
-        "picomatch": "^2.0.5"
-      }
-    },
-    "miller-rabin": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
-      "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
-      "dev": true,
-      "requires": {
-        "bn.js": "^4.0.0",
-        "brorand": "^1.0.1"
-      },
-      "dependencies": {
-        "bn.js": {
-          "version": "4.11.9",
-          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
-          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
-          "dev": true
-        }
+        "braces": "^3.0.2",
+        "picomatch": "^2.3.1"
       }
     },
     "mime": {
@@ -6775,18 +17405,18 @@
       "dev": true
     },
     "mime-db": {
-      "version": "1.44.0",
-      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
-      "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==",
+      "version": "1.52.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
+      "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
       "dev": true
     },
     "mime-types": {
-      "version": "2.1.27",
-      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
-      "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
+      "version": "2.1.35",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
+      "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
       "dev": true,
       "requires": {
-        "mime-db": "1.44.0"
+        "mime-db": "1.52.0"
       }
     },
     "mimic-fn": {
@@ -6796,60 +17426,12 @@
       "dev": true
     },
     "mini-css-extract-plugin": {
-      "version": "0.10.0",
-      "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.10.0.tgz",
-      "integrity": "sha512-QgKgJBjaJhxVPwrLNqqwNS0AGkuQQ31Hp4xGXEK/P7wehEg6qmNtReHKai3zRXqY60wGVWLYcOMJK2b98aGc3A==",
+      "version": "2.7.2",
+      "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.2.tgz",
+      "integrity": "sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw==",
       "dev": true,
       "requires": {
-        "loader-utils": "^1.1.0",
-        "normalize-url": "1.9.1",
-        "schema-utils": "^1.0.0",
-        "webpack-sources": "^1.1.0"
-      },
-      "dependencies": {
-        "json5": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
-          "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
-          "dev": true,
-          "requires": {
-            "minimist": "^1.2.0"
-          }
-        },
-        "loader-utils": {
-          "version": "1.4.0",
-          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
-          "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
-          "dev": true,
-          "requires": {
-            "big.js": "^5.2.2",
-            "emojis-list": "^3.0.0",
-            "json5": "^1.0.1"
-          }
-        },
-        "normalize-url": {
-          "version": "1.9.1",
-          "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
-          "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=",
-          "dev": true,
-          "requires": {
-            "object-assign": "^4.0.1",
-            "prepend-http": "^1.0.0",
-            "query-string": "^4.1.0",
-            "sort-keys": "^1.0.0"
-          }
-        },
-        "schema-utils": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
-          "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
-          "dev": true,
-          "requires": {
-            "ajv": "^6.1.0",
-            "ajv-errors": "^1.0.0",
-            "ajv-keywords": "^3.1.0"
-          }
-        }
+        "schema-utils": "^4.0.0"
       }
     },
     "minimalistic-assert": {
@@ -6858,16 +17440,10 @@
       "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
       "dev": true
     },
-    "minimalistic-crypto-utils": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
-      "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
-      "dev": true
-    },
     "minimatch": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
-      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
       "requires": {
         "brace-expansion": "^1.1.7"
       }
@@ -6878,9 +17454,9 @@
       "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
     },
     "minipass": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz",
-      "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==",
+      "version": "3.1.6",
+      "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz",
+      "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==",
       "dev": true,
       "requires": {
         "yallist": "^4.0.0"
@@ -6895,6 +17471,18 @@
         "minipass": "^3.0.0"
       }
     },
+    "minipass-fetch": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz",
+      "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==",
+      "dev": true,
+      "requires": {
+        "encoding": "^0.1.12",
+        "minipass": "^3.1.0",
+        "minipass-sized": "^1.0.3",
+        "minizlib": "^2.0.0"
+      }
+    },
     "minipass-flush": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz",
@@ -6904,6 +17492,16 @@
         "minipass": "^3.0.0"
       }
     },
+    "minipass-json-stream": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz",
+      "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==",
+      "dev": true,
+      "requires": {
+        "jsonparse": "^1.3.1",
+        "minipass": "^3.0.0"
+      }
+    },
     "minipass-pipeline": {
       "version": "1.2.4",
       "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz",
@@ -6913,6 +17511,15 @@
         "minipass": "^3.0.0"
       }
     },
+    "minipass-sized": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz",
+      "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==",
+      "dev": true,
+      "requires": {
+        "minipass": "^3.0.0"
+      }
+    },
     "minizlib": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
@@ -6923,45 +17530,6 @@
         "yallist": "^4.0.0"
       }
     },
-    "mississippi": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
-      "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==",
-      "dev": true,
-      "requires": {
-        "concat-stream": "^1.5.0",
-        "duplexify": "^3.4.2",
-        "end-of-stream": "^1.1.0",
-        "flush-write-stream": "^1.0.0",
-        "from2": "^2.1.0",
-        "parallel-transform": "^1.1.0",
-        "pump": "^3.0.0",
-        "pumpify": "^1.3.3",
-        "stream-each": "^1.1.0",
-        "through2": "^2.0.0"
-      }
-    },
-    "mixin-deep": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
-      "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
-      "dev": true,
-      "requires": {
-        "for-in": "^1.0.2",
-        "is-extendable": "^1.0.1"
-      },
-      "dependencies": {
-        "is-extendable": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
-          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
-          "dev": true,
-          "requires": {
-            "is-plain-object": "^2.0.4"
-          }
-        }
-      }
-    },
     "mkdirp": {
       "version": "0.5.5",
       "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
@@ -6972,56 +17540,23 @@
       }
     },
     "moment": {
-      "version": "2.29.2",
-      "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.2.tgz",
-      "integrity": "sha512-UgzG4rvxYpN15jgCmVJwac49h9ly9NurikMWGPdVxm8GZD6XjkKPxDTjQQ43gtGgnV3X0cAyWDdP2Wexoquifg=="
+      "version": "2.29.4",
+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
+      "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
     },
     "moment-timezone": {
-      "version": "0.5.31",
-      "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.31.tgz",
-      "integrity": "sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==",
+      "version": "0.5.35",
+      "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.35.tgz",
+      "integrity": "sha512-cY/pBOEXepQvlgli06ttCTKcIf8cD1nmNwOKQQAdHBqYApQSpAqotBMX0RJZNgMp6i0PlZuf1mFtnlyEkwyvFw==",
       "requires": {
         "moment": ">= 2.9.0"
       }
     },
-    "move-concurrently": {
+    "mrmime": {
       "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
-      "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=",
-      "dev": true,
-      "requires": {
-        "aproba": "^1.1.1",
-        "copy-concurrently": "^1.0.0",
-        "fs-write-stream-atomic": "^1.0.8",
-        "mkdirp": "^0.5.1",
-        "rimraf": "^2.5.4",
-        "run-queue": "^1.0.3"
-      },
-      "dependencies": {
-        "glob": {
-          "version": "7.1.6",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
-        "rimraf": {
-          "version": "2.7.1",
-          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
-          "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
-          "dev": true,
-          "requires": {
-            "glob": "^7.1.3"
-          }
-        }
-      }
+      "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz",
+      "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==",
+      "dev": true
     },
     "ms": {
       "version": "2.1.2",
@@ -7029,57 +17564,65 @@
       "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
     },
     "multicast-dns": {
-      "version": "6.2.3",
-      "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz",
-      "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==",
+      "version": "7.2.5",
+      "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz",
+      "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==",
       "dev": true,
       "requires": {
-        "dns-packet": "^1.3.1",
+        "dns-packet": "^5.2.2",
         "thunky": "^1.0.2"
       }
     },
-    "multicast-dns-service-types": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz",
-      "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=",
-      "dev": true
-    },
     "mute-stream": {
       "version": "0.0.8",
       "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
       "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
       "dev": true
     },
-    "nanomatch": {
-      "version": "1.2.13",
-      "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
-      "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
+    "nanoid": {
+      "version": "3.3.4",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
+      "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
+      "dev": true
+    },
+    "needle": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz",
+      "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==",
       "dev": true,
+      "optional": true,
       "requires": {
-        "arr-diff": "^4.0.0",
-        "array-unique": "^0.3.2",
-        "define-property": "^2.0.2",
-        "extend-shallow": "^3.0.2",
-        "fragment-cache": "^0.2.1",
-        "is-windows": "^1.0.2",
-        "kind-of": "^6.0.2",
-        "object.pick": "^1.3.0",
-        "regex-not": "^1.0.0",
-        "snapdragon": "^0.8.1",
-        "to-regex": "^3.0.1"
+        "debug": "^3.2.6",
+        "iconv-lite": "^0.6.3",
+        "sax": "^1.2.4"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "3.2.7",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
+          "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "ms": "^2.1.1"
+          }
+        },
+        "iconv-lite": {
+          "version": "0.6.3",
+          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+          "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "safer-buffer": ">= 2.1.2 < 3.0.0"
+          }
+        }
       }
     },
-    "native-request": {
-      "version": "1.0.8",
-      "resolved": "https://registry.npmjs.org/native-request/-/native-request-1.0.8.tgz",
-      "integrity": "sha512-vU2JojJVelUGp6jRcLwToPoWGxSx23z/0iX+I77J3Ht17rf2INGjrhOoQnjVo60nQd8wVsgzKkPfRXBiVdD2ag==",
-      "dev": true,
-      "optional": true
-    },
     "negotiator": {
-      "version": "0.6.2",
-      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
-      "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
+      "version": "0.6.3",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
+      "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
       "dev": true
     },
     "neo-async": {
@@ -7088,12 +17631,6 @@
       "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
       "dev": true
     },
-    "next-tick": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
-      "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
-      "dev": true
-    },
     "ng-daterangepicker": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/ng-daterangepicker/-/ng-daterangepicker-1.1.0.tgz",
@@ -7117,118 +17654,118 @@
       "integrity": "sha512-rytCRBhvuudj614Kfj9GoIVQDrFuLvHSMP1YrMwTmR1SNkNJZOpGKmaSDCCBrNDkSrGouzMWBlFbl1UDBBsiqw==",
       "requires": {
         "tslib": "^1.10.0"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "1.14.1",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+          "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+        }
       }
     },
-    "nice-try": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
-      "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
-      "dev": true
-    },
-    "node-fetch-npm": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/node-fetch-npm/-/node-fetch-npm-2.0.4.tgz",
-      "integrity": "sha512-iOuIQDWDyjhv9qSDrj9aq/klt6F9z1p2otB3AV7v3zBDcL/x+OfGsvGQZZCcMZbUf4Ujw1xGNQkjvGnVT22cKg==",
+    "nice-napi": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz",
+      "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==",
       "dev": true,
+      "optional": true,
       "requires": {
-        "encoding": "^0.1.11",
-        "json-parse-better-errors": "^1.0.0",
-        "safe-buffer": "^5.1.1"
+        "node-addon-api": "^3.0.0",
+        "node-gyp-build": "^4.2.2"
       }
     },
+    "node-addon-api": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
+      "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==",
+      "dev": true,
+      "optional": true
+    },
     "node-forge": {
-      "version": "0.10.0",
-      "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz",
-      "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==",
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz",
+      "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==",
       "dev": true
     },
-    "node-libs-browser": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
-      "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==",
+    "node-gyp": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz",
+      "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==",
       "dev": true,
       "requires": {
-        "assert": "^1.1.1",
-        "browserify-zlib": "^0.2.0",
-        "buffer": "^4.3.0",
-        "console-browserify": "^1.1.0",
-        "constants-browserify": "^1.0.0",
-        "crypto-browserify": "^3.11.0",
-        "domain-browser": "^1.1.1",
-        "events": "^3.0.0",
-        "https-browserify": "^1.0.0",
-        "os-browserify": "^0.3.0",
-        "path-browserify": "0.0.1",
-        "process": "^0.11.10",
-        "punycode": "^1.2.4",
-        "querystring-es3": "^0.2.0",
-        "readable-stream": "^2.3.3",
-        "stream-browserify": "^2.0.1",
-        "stream-http": "^2.7.2",
-        "string_decoder": "^1.0.0",
-        "timers-browserify": "^2.0.4",
-        "tty-browserify": "0.0.0",
-        "url": "^0.11.0",
-        "util": "^0.11.0",
-        "vm-browserify": "^1.0.1"
+        "env-paths": "^2.2.0",
+        "glob": "^7.1.4",
+        "graceful-fs": "^4.2.3",
+        "nopt": "^5.0.0",
+        "npmlog": "^4.1.2",
+        "request": "^2.88.2",
+        "rimraf": "^3.0.2",
+        "semver": "^7.3.2",
+        "tar": "^6.0.2",
+        "which": "^2.0.2"
       },
       "dependencies": {
-        "punycode": {
-          "version": "1.4.1",
-          "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
-          "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
-          "dev": true
+        "glob": {
+          "version": "7.2.3",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+          "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.1.1",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        },
+        "semver": {
+          "version": "7.3.7",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+          "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
         }
       }
     },
-    "node-releases": {
-      "version": "1.1.65",
-      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.65.tgz",
-      "integrity": "sha512-YpzJOe2WFIW0V4ZkJQd/DGR/zdVwc/pI4Nl1CZrBO19FdRcSTmsuhdttw9rsTzzJLrNcSloLiBbEYx1C4f6gpA==",
-      "dev": true
+    "node-gyp-build": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz",
+      "integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==",
+      "dev": true,
+      "optional": true
     },
-    "normalize-package-data": {
-      "version": "2.5.0",
-      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
-      "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
+    "node-releases": {
+      "version": "2.0.10",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.10.tgz",
+      "integrity": "sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w=="
+    },
+    "nopt": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz",
+      "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==",
       "dev": true,
       "requires": {
-        "hosted-git-info": "^2.1.4",
-        "resolve": "^1.10.0",
-        "semver": "2 || 3 || 4 || 5",
-        "validate-npm-package-license": "^3.0.1"
-      },
-      "dependencies": {
-        "hosted-git-info": {
-          "version": "2.8.9",
-          "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
-          "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
-          "dev": true
-        }
+        "abbrev": "1"
       }
     },
     "normalize-path": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
-      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-      "dev": true
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
     },
     "normalize-range": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
-      "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
-      "dev": true
-    },
-    "normalize-url": {
-      "version": "3.3.0",
-      "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz",
-      "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==",
+      "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
       "dev": true
     },
     "npm-bundled": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz",
-      "integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==",
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz",
+      "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==",
       "dev": true,
       "requires": {
         "npm-normalize-package-bin": "^1.0.1"
@@ -7258,12 +17795,12 @@
       "dev": true
     },
     "npm-package-arg": {
-      "version": "8.0.1",
-      "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.0.1.tgz",
-      "integrity": "sha512-/h5Fm6a/exByzFSTm7jAyHbgOqErl9qSNJDQF32Si/ZzgwT2TERVxRxn3Jurw1wflgyVVAxnFR4fRHPM7y1ClQ==",
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.0.tgz",
+      "integrity": "sha512-/ep6QDxBkm9HvOhOg0heitSd7JHA1U7y1qhhlRlteYYAi9Pdb/ZV7FW5aHpkrpM8+P+4p/jjR8zCyKPBMBjSig==",
       "dev": true,
       "requires": {
-        "hosted-git-info": "^3.0.2",
+        "hosted-git-info": "^3.0.6",
         "semver": "^7.0.0",
         "validate-npm-package-name": "^3.0.0"
       },
@@ -7277,14 +17814,31 @@
       }
     },
     "npm-packlist": {
-      "version": "1.4.8",
-      "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz",
-      "integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==",
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-2.2.2.tgz",
+      "integrity": "sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg==",
       "dev": true,
       "requires": {
-        "ignore-walk": "^3.0.1",
-        "npm-bundled": "^1.0.1",
+        "glob": "^7.1.6",
+        "ignore-walk": "^3.0.3",
+        "npm-bundled": "^1.1.1",
         "npm-normalize-package-bin": "^1.0.1"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "7.2.3",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+          "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.1.1",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        }
       }
     },
     "npm-pick-manifest": {
@@ -7307,83 +17861,55 @@
       }
     },
     "npm-registry-fetch": {
-      "version": "4.0.7",
-      "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-4.0.7.tgz",
-      "integrity": "sha512-cny9v0+Mq6Tjz+e0erFAB+RYJ/AVGzkjnISiobqP8OWj9c9FLoZZu8/SPSKJWE17F1tk4018wfjV+ZbIbqC7fQ==",
+      "version": "9.0.0",
+      "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-9.0.0.tgz",
+      "integrity": "sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA==",
       "dev": true,
       "requires": {
-        "JSONStream": "^1.3.4",
-        "bluebird": "^3.5.1",
-        "figgy-pudding": "^3.4.1",
-        "lru-cache": "^5.1.1",
-        "make-fetch-happen": "^5.0.0",
-        "npm-package-arg": "^6.1.0",
-        "safe-buffer": "^5.2.0"
-      },
-      "dependencies": {
-        "hosted-git-info": {
-          "version": "2.8.9",
-          "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
-          "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
-          "dev": true
-        },
-        "lru-cache": {
-          "version": "5.1.1",
-          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
-          "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
-          "dev": true,
-          "requires": {
-            "yallist": "^3.0.2"
-          }
-        },
-        "npm-package-arg": {
-          "version": "6.1.1",
-          "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz",
-          "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==",
-          "dev": true,
-          "requires": {
-            "hosted-git-info": "^2.7.1",
-            "osenv": "^0.1.5",
-            "semver": "^5.6.0",
-            "validate-npm-package-name": "^3.0.0"
-          }
-        },
-        "safe-buffer": {
-          "version": "5.2.1",
-          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-          "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
-          "dev": true
-        },
-        "yallist": {
-          "version": "3.1.1",
-          "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
-          "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
-          "dev": true
-        }
+        "@npmcli/ci-detect": "^1.0.0",
+        "lru-cache": "^6.0.0",
+        "make-fetch-happen": "^8.0.9",
+        "minipass": "^3.1.3",
+        "minipass-fetch": "^1.3.0",
+        "minipass-json-stream": "^1.0.1",
+        "minizlib": "^2.0.0",
+        "npm-package-arg": "^8.0.0"
       }
     },
     "npm-run-path": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
-      "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
+      "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
       "dev": true,
       "requires": {
-        "path-key": "^2.0.0"
+        "path-key": "^3.0.0"
+      }
+    },
+    "npmlog": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+      "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
+      "dev": true,
+      "requires": {
+        "are-we-there-yet": "~1.1.2",
+        "console-control-strings": "~1.1.0",
+        "gauge": "~2.7.3",
+        "set-blocking": "~2.0.0"
       }
     },
     "nth-check": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
-      "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
+      "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
       "dev": true,
       "requires": {
-        "boolbase": "~1.0.0"
+        "boolbase": "^1.0.0"
       }
     },
-    "num2fraction": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
-      "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=",
+    "number-is-nan": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+      "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==",
       "dev": true
     },
     "oauth-sign": {
@@ -7398,133 +17924,12 @@
       "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
       "dev": true
     },
-    "object-copy": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
-      "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
-      "dev": true,
-      "requires": {
-        "copy-descriptor": "^0.1.0",
-        "define-property": "^0.2.5",
-        "kind-of": "^3.0.3"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "0.2.5",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^0.1.0"
-          }
-        },
-        "kind-of": {
-          "version": "3.2.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-          "dev": true,
-          "requires": {
-            "is-buffer": "^1.1.5"
-          }
-        }
-      }
-    },
     "object-inspect": {
-      "version": "1.8.0",
-      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
-      "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==",
+      "version": "1.12.3",
+      "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
+      "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
       "dev": true
     },
-    "object-is": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.3.tgz",
-      "integrity": "sha512-teyqLvFWzLkq5B9ki8FVWA902UER2qkxmdA4nLf+wjOLAWgxzCWZNCxpDq9MvE8MmhWNr+I8w3BN49Vx36Y6Xg==",
-      "dev": true,
-      "requires": {
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.18.0-next.1"
-      },
-      "dependencies": {
-        "es-abstract": {
-          "version": "1.18.0-next.1",
-          "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz",
-          "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==",
-          "dev": true,
-          "requires": {
-            "es-to-primitive": "^1.2.1",
-            "function-bind": "^1.1.1",
-            "has": "^1.0.3",
-            "has-symbols": "^1.0.1",
-            "is-callable": "^1.2.2",
-            "is-negative-zero": "^2.0.0",
-            "is-regex": "^1.1.1",
-            "object-inspect": "^1.8.0",
-            "object-keys": "^1.1.1",
-            "object.assign": "^4.1.1",
-            "string.prototype.trimend": "^1.0.1",
-            "string.prototype.trimstart": "^1.0.1"
-          }
-        }
-      }
-    },
-    "object-keys": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
-      "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
-      "dev": true
-    },
-    "object-visit": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
-      "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
-      "dev": true,
-      "requires": {
-        "isobject": "^3.0.0"
-      }
-    },
-    "object.assign": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz",
-      "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==",
-      "dev": true,
-      "requires": {
-        "call-bind": "^1.0.0",
-        "define-properties": "^1.1.3",
-        "has-symbols": "^1.0.1",
-        "object-keys": "^1.1.1"
-      }
-    },
-    "object.getownpropertydescriptors": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.0.tgz",
-      "integrity": "sha512-Z53Oah9A3TdLoblT7VKJaTDdXdT+lQO+cNpKVnya5JDe9uLvzu1YyY1yFDFrcxrlRgWrEFH0jJtD/IbuwjcEVg==",
-      "dev": true,
-      "requires": {
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.17.0-next.1"
-      }
-    },
-    "object.pick": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
-      "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
-      "dev": true,
-      "requires": {
-        "isobject": "^3.0.1"
-      }
-    },
-    "object.values": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.1.tgz",
-      "integrity": "sha512-WTa54g2K8iu0kmS/us18jEmdv1a4Wi//BZ/DTVYEcH0XhLM5NYdpDHja3gt57VrZLcNAO2WGA+KpWsDBaHt6eA==",
-      "dev": true,
-      "requires": {
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.17.0-next.1",
-        "function-bind": "^1.1.1",
-        "has": "^1.0.3"
-      }
-    },
     "obuf": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz",
@@ -7532,9 +17937,9 @@
       "dev": true
     },
     "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==",
       "dev": true,
       "requires": {
         "ee-first": "1.1.1"
@@ -7564,9 +17969,9 @@
       }
     },
     "open": {
-      "version": "7.2.0",
-      "resolved": "https://registry.npmjs.org/open/-/open-7.2.0.tgz",
-      "integrity": "sha512-4HeyhxCvBTI5uBePsAdi55C5fmqnWZ2e2MlmvWi5KW5tdH5rxoiv/aMtbeVxKZc3eWkT1GymMnLG8XC4Rq4TDQ==",
+      "version": "7.4.0",
+      "resolved": "https://registry.npmjs.org/open/-/open-7.4.0.tgz",
+      "integrity": "sha512-PGoBCX/lclIWlpS/R2PQuIR4NJoXh6X5AwVzE7WXnWRGvHg7+4TBCgsujUgiPpm0K1y4qvQeWnCWVTpTKZBtvA==",
       "dev": true,
       "requires": {
         "is-docker": "^2.0.0",
@@ -7579,35 +17984,18 @@
       "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==",
       "dev": true
     },
-    "opn": {
-      "version": "5.5.0",
-      "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz",
-      "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==",
-      "dev": true,
-      "requires": {
-        "is-wsl": "^1.1.0"
-      },
-      "dependencies": {
-        "is-wsl": {
-          "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
-          "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=",
-          "dev": true
-        }
-      }
-    },
     "ora": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/ora/-/ora-5.0.0.tgz",
-      "integrity": "sha512-s26qdWqke2kjN/wC4dy+IQPBIMWBJlSU/0JZhk30ZDBLelW25rv66yutUWARMigpGPzcXHb+Nac5pNhN/WsARw==",
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz",
+      "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==",
       "dev": true,
       "requires": {
+        "bl": "^4.0.3",
         "chalk": "^4.1.0",
         "cli-cursor": "^3.1.0",
-        "cli-spinners": "^2.4.0",
+        "cli-spinners": "^2.5.0",
         "is-interactive": "^1.0.0",
         "log-symbols": "^4.0.0",
-        "mute-stream": "0.0.8",
         "strip-ansi": "^6.0.0",
         "wcwidth": "^1.0.1"
       },
@@ -7622,9 +18010,9 @@
           }
         },
         "chalk": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
-          "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
           "dev": true,
           "requires": {
             "ansi-styles": "^4.1.0",
@@ -7663,53 +18051,17 @@
         }
       }
     },
-    "original": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz",
-      "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==",
-      "dev": true,
-      "requires": {
-        "url-parse": "^1.4.3"
-      }
-    },
-    "os-browserify": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
-      "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=",
-      "dev": true
-    },
-    "os-homedir": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
-      "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
-      "dev": true
-    },
     "os-tmpdir": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
       "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
       "dev": true
     },
-    "osenv": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
-      "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
-      "dev": true,
-      "requires": {
-        "os-homedir": "^1.0.0",
-        "os-tmpdir": "^1.0.0"
-      }
-    },
-    "p-finally": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
-      "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
-      "dev": true
-    },
     "p-limit": {
       "version": "2.3.0",
       "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
       "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
+      "dev": true,
       "requires": {
         "p-try": "^2.0.0"
       }
@@ -7718,6 +18070,7 @@
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
       "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
+      "dev": true,
       "requires": {
         "p-limit": "^2.2.0"
       }
@@ -7732,211 +18085,60 @@
       }
     },
     "p-retry": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz",
-      "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==",
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz",
+      "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==",
       "dev": true,
       "requires": {
-        "retry": "^0.12.0"
+        "@types/retry": "0.12.0",
+        "retry": "^0.13.1"
+      },
+      "dependencies": {
+        "retry": {
+          "version": "0.13.1",
+          "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
+          "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==",
+          "dev": true
+        }
       }
     },
     "p-try": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
+      "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
+      "dev": true
     },
     "pacote": {
-      "version": "9.5.12",
-      "resolved": "https://registry.npmjs.org/pacote/-/pacote-9.5.12.tgz",
-      "integrity": "sha512-BUIj/4kKbwWg4RtnBncXPJd15piFSVNpTzY0rysSr3VnMowTYgkGKcaHrbReepAkjTr8lH2CVWRi58Spg2CicQ==",
+      "version": "11.2.4",
+      "resolved": "https://registry.npmjs.org/pacote/-/pacote-11.2.4.tgz",
+      "integrity": "sha512-GfTeVQGJ6WyBQbQD4t3ocHbyOmTQLmWjkCKSZPmKiGFKYKNUaM5U2gbLzUW8WG1XmS9yQFnsTFA0k3o1+q4klQ==",
       "dev": true,
       "requires": {
-        "bluebird": "^3.5.3",
-        "cacache": "^12.0.2",
-        "chownr": "^1.1.2",
-        "figgy-pudding": "^3.5.1",
-        "get-stream": "^4.1.0",
-        "glob": "^7.1.3",
+        "@npmcli/git": "^2.0.1",
+        "@npmcli/installed-package-contents": "^1.0.5",
+        "@npmcli/promise-spawn": "^1.2.0",
+        "@npmcli/run-script": "^1.3.0",
+        "cacache": "^15.0.5",
+        "chownr": "^2.0.0",
+        "fs-minipass": "^2.1.0",
         "infer-owner": "^1.0.4",
-        "lru-cache": "^5.1.1",
-        "make-fetch-happen": "^5.0.0",
-        "minimatch": "^3.0.4",
-        "minipass": "^2.3.5",
-        "mississippi": "^3.0.0",
-        "mkdirp": "^0.5.1",
-        "normalize-package-data": "^2.4.0",
-        "npm-normalize-package-bin": "^1.0.0",
-        "npm-package-arg": "^6.1.0",
-        "npm-packlist": "^1.1.12",
-        "npm-pick-manifest": "^3.0.0",
-        "npm-registry-fetch": "^4.0.0",
-        "osenv": "^0.1.5",
-        "promise-inflight": "^1.0.1",
+        "minipass": "^3.1.3",
+        "mkdirp": "^1.0.3",
+        "npm-package-arg": "^8.0.1",
+        "npm-packlist": "^2.1.4",
+        "npm-pick-manifest": "^6.0.0",
+        "npm-registry-fetch": "^9.0.0",
         "promise-retry": "^1.1.1",
-        "protoduck": "^5.0.1",
-        "rimraf": "^2.6.2",
-        "safe-buffer": "^5.1.2",
-        "semver": "^5.6.0",
-        "ssri": "^6.0.1",
-        "tar": "^4.4.10",
-        "unique-filename": "^1.1.1",
-        "which": "^1.3.1"
+        "read-package-json-fast": "^1.1.3",
+        "rimraf": "^3.0.2",
+        "ssri": "^8.0.0",
+        "tar": "^6.1.0"
       },
       "dependencies": {
-        "cacache": {
-          "version": "12.0.4",
-          "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz",
-          "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==",
-          "dev": true,
-          "requires": {
-            "bluebird": "^3.5.5",
-            "chownr": "^1.1.1",
-            "figgy-pudding": "^3.5.1",
-            "glob": "^7.1.4",
-            "graceful-fs": "^4.1.15",
-            "infer-owner": "^1.0.3",
-            "lru-cache": "^5.1.1",
-            "mississippi": "^3.0.0",
-            "mkdirp": "^0.5.1",
-            "move-concurrently": "^1.0.1",
-            "promise-inflight": "^1.0.1",
-            "rimraf": "^2.6.3",
-            "ssri": "^6.0.1",
-            "unique-filename": "^1.1.1",
-            "y18n": "^4.0.0"
-          }
-        },
-        "chownr": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
-          "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
-          "dev": true
-        },
-        "fs-minipass": {
-          "version": "1.2.7",
-          "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
-          "integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==",
-          "dev": true,
-          "requires": {
-            "minipass": "^2.6.0"
-          }
-        },
-        "glob": {
-          "version": "7.1.6",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
-        "hosted-git-info": {
-          "version": "2.8.9",
-          "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz",
-          "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
-          "dev": true
-        },
-        "lru-cache": {
-          "version": "5.1.1",
-          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
-          "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
-          "dev": true,
-          "requires": {
-            "yallist": "^3.0.2"
-          }
-        },
-        "minipass": {
-          "version": "2.9.0",
-          "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
-          "integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
-          "dev": true,
-          "requires": {
-            "safe-buffer": "^5.1.2",
-            "yallist": "^3.0.0"
-          }
-        },
-        "minizlib": {
-          "version": "1.3.3",
-          "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz",
-          "integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
-          "dev": true,
-          "requires": {
-            "minipass": "^2.9.0"
-          }
-        },
-        "npm-package-arg": {
-          "version": "6.1.1",
-          "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-6.1.1.tgz",
-          "integrity": "sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg==",
-          "dev": true,
-          "requires": {
-            "hosted-git-info": "^2.7.1",
-            "osenv": "^0.1.5",
-            "semver": "^5.6.0",
-            "validate-npm-package-name": "^3.0.0"
-          }
-        },
-        "npm-pick-manifest": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz",
-          "integrity": "sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw==",
-          "dev": true,
-          "requires": {
-            "figgy-pudding": "^3.5.1",
-            "npm-package-arg": "^6.0.0",
-            "semver": "^5.4.1"
-          }
-        },
-        "rimraf": {
-          "version": "2.7.1",
-          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
-          "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
-          "dev": true,
-          "requires": {
-            "glob": "^7.1.3"
-          }
-        },
-        "ssri": {
-          "version": "6.0.2",
-          "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz",
-          "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==",
-          "dev": true,
-          "requires": {
-            "figgy-pudding": "^3.5.1"
-          }
-        },
-        "tar": {
-          "version": "4.4.19",
-          "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.19.tgz",
-          "integrity": "sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA==",
-          "dev": true,
-          "requires": {
-            "chownr": "^1.1.4",
-            "fs-minipass": "^1.2.7",
-            "minipass": "^2.9.0",
-            "minizlib": "^1.3.3",
-            "mkdirp": "^0.5.5",
-            "safe-buffer": "^5.2.1",
-            "yallist": "^3.1.1"
-          },
-          "dependencies": {
-            "safe-buffer": {
-              "version": "5.2.1",
-              "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
-              "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
-              "dev": true
-            }
-          }
-        },
-        "yallist": {
-          "version": "3.1.1",
-          "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
-          "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
+        "mkdirp": {
+          "version": "1.0.4",
+          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
+          "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
           "dev": true
         }
       }
@@ -7947,46 +18149,67 @@
       "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
       "dev": true
     },
-    "parallel-transform": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz",
-      "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==",
+    "parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
       "dev": true,
       "requires": {
-        "cyclist": "^1.0.1",
-        "inherits": "^2.0.3",
-        "readable-stream": "^2.1.5"
-      }
-    },
-    "parse-asn1": {
-      "version": "5.1.6",
-      "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz",
-      "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==",
-      "dev": true,
-      "requires": {
-        "asn1.js": "^5.2.0",
-        "browserify-aes": "^1.0.0",
-        "evp_bytestokey": "^1.0.0",
-        "pbkdf2": "^3.0.3",
-        "safe-buffer": "^5.1.1"
+        "callsites": "^3.0.0"
       }
     },
     "parse-json": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz",
-      "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=",
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
       "dev": true,
       "requires": {
+        "@babel/code-frame": "^7.0.0",
         "error-ex": "^1.3.1",
-        "json-parse-better-errors": "^1.0.1"
+        "json-parse-even-better-errors": "^2.3.0",
+        "lines-and-columns": "^1.1.6"
       }
     },
+    "parse-node-version": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz",
+      "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==",
+      "dev": true
+    },
     "parse5": {
       "version": "5.1.1",
       "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
       "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
       "optional": true
     },
+    "parse5-html-rewriting-stream": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz",
+      "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==",
+      "dev": true,
+      "requires": {
+        "entities": "^4.3.0",
+        "parse5": "^7.0.0",
+        "parse5-sax-parser": "^7.0.0"
+      },
+      "dependencies": {
+        "entities": {
+          "version": "4.4.0",
+          "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
+          "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
+          "dev": true
+        },
+        "parse5": {
+          "version": "7.1.2",
+          "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
+          "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
+          "dev": true,
+          "requires": {
+            "entities": "^4.4.0"
+          }
+        }
+      }
+    },
     "parse5-htmlparser2-tree-adapter": {
       "version": "6.0.1",
       "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz",
@@ -8004,61 +18227,64 @@
         }
       }
     },
+    "parse5-sax-parser": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz",
+      "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==",
+      "dev": true,
+      "requires": {
+        "parse5": "^7.0.0"
+      },
+      "dependencies": {
+        "entities": {
+          "version": "4.4.0",
+          "resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
+          "integrity": "sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==",
+          "dev": true
+        },
+        "parse5": {
+          "version": "7.1.2",
+          "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
+          "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
+          "dev": true,
+          "requires": {
+            "entities": "^4.4.0"
+          }
+        }
+      }
+    },
     "parseurl": {
       "version": "1.3.3",
       "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
       "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
       "dev": true
     },
-    "pascalcase": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
-      "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
-      "dev": true
-    },
-    "path-browserify": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
-      "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==",
-      "dev": true
-    },
-    "path-dirname": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
-      "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
-      "dev": true
-    },
     "path-exists": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
+      "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
+      "dev": true
     },
     "path-is-absolute": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
       "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
     },
-    "path-is-inside": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
-      "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
-      "dev": true
-    },
     "path-key": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
-      "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
+      "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
       "dev": true
     },
     "path-parse": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
-      "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
     },
     "path-to-regexp": {
       "version": "0.1.7",
       "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
-      "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
+      "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==",
       "dev": true
     },
     "path-type": {
@@ -8067,769 +18293,139 @@
       "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
       "dev": true
     },
-    "pbkdf2": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz",
-      "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==",
-      "dev": true,
-      "requires": {
-        "create-hash": "^1.1.2",
-        "create-hmac": "^1.1.4",
-        "ripemd160": "^2.0.1",
-        "safe-buffer": "^5.0.1",
-        "sha.js": "^2.4.8"
-      }
-    },
     "performance-now": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
       "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
       "dev": true
     },
+    "picocolors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
+    },
     "picomatch": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
-      "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==",
-      "dev": true
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
     },
     "pify": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
       "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
-      "dev": true
+      "dev": true,
+      "optional": true
     },
-    "pinkie": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
-      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
-      "dev": true
-    },
-    "pinkie-promise": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
-      "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+    "piscina": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/piscina/-/piscina-3.2.0.tgz",
+      "integrity": "sha512-yn/jMdHRw+q2ZJhFhyqsmANcbF6V2QwmD84c6xRau+QpQOmtrBCoRGdvTfeuFDYXB5W2m6MfLkjkvQa9lUSmIA==",
       "dev": true,
       "requires": {
-        "pinkie": "^2.0.0"
+        "eventemitter-asyncresource": "^1.0.0",
+        "hdr-histogram-js": "^2.0.1",
+        "hdr-histogram-percentiles-obj": "^3.0.0",
+        "nice-napi": "^1.0.2"
       }
     },
     "pkg-dir": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz",
-      "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==",
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
+      "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
       "dev": true,
       "requires": {
-        "find-up": "^3.0.0"
-      },
-      "dependencies": {
-        "find-up": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
-          "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
-          "dev": true,
-          "requires": {
-            "locate-path": "^3.0.0"
-          }
-        },
-        "locate-path": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
-          "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
-          "dev": true,
-          "requires": {
-            "p-locate": "^3.0.0",
-            "path-exists": "^3.0.0"
-          }
-        },
-        "p-locate": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
-          "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
-          "dev": true,
-          "requires": {
-            "p-limit": "^2.0.0"
-          }
-        },
-        "path-exists": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
-          "dev": true
-        }
+        "find-up": "^4.0.0"
       }
     },
-    "pnp-webpack-plugin": {
-      "version": "1.6.4",
-      "resolved": "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz",
-      "integrity": "sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==",
-      "dev": true,
-      "requires": {
-        "ts-pnp": "^1.1.6"
-      }
-    },
-    "portfinder": {
-      "version": "1.0.28",
-      "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz",
-      "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==",
-      "dev": true,
-      "requires": {
-        "async": "^2.6.2",
-        "debug": "^3.1.1",
-        "mkdirp": "^0.5.5"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "3.2.6",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
-          "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        }
-      }
-    },
-    "posix-character-classes": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
-      "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
-      "dev": true
-    },
     "postcss": {
-      "version": "7.0.32",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz",
-      "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==",
+      "version": "8.4.21",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz",
+      "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
       "dev": true,
       "requires": {
-        "chalk": "^2.4.2",
-        "source-map": "^0.6.1",
-        "supports-color": "^6.1.0"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "6.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
-          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^3.0.0"
-          }
-        }
-      }
-    },
-    "postcss-calc": {
-      "version": "7.0.5",
-      "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-7.0.5.tgz",
-      "integrity": "sha512-1tKHutbGtLtEZF6PT4JSihCHfIVldU72mZ8SdZHIYriIZ9fh9k9aWSppaT8rHsyI3dX+KSR+W+Ix9BMY3AODrg==",
-      "dev": true,
-      "requires": {
-        "postcss": "^7.0.27",
-        "postcss-selector-parser": "^6.0.2",
-        "postcss-value-parser": "^4.0.2"
-      }
-    },
-    "postcss-colormin": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-4.0.3.tgz",
-      "integrity": "sha512-WyQFAdDZpExQh32j0U0feWisZ0dmOtPl44qYmJKkq9xFWY3p+4qnRzCHeNrkeRhwPHz9bQ3mo0/yVkaply0MNw==",
-      "dev": true,
-      "requires": {
-        "browserslist": "^4.0.0",
-        "color": "^3.0.0",
-        "has": "^1.0.0",
-        "postcss": "^7.0.0",
-        "postcss-value-parser": "^3.0.0"
-      },
-      "dependencies": {
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-          "dev": true
-        }
-      }
-    },
-    "postcss-convert-values": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-4.0.1.tgz",
-      "integrity": "sha512-Kisdo1y77KUC0Jmn0OXU/COOJbzM8cImvw1ZFsBgBgMgb1iL23Zs/LXRe3r+EZqM3vGYKdQ2YJVQ5VkJI+zEJQ==",
-      "dev": true,
-      "requires": {
-        "postcss": "^7.0.0",
-        "postcss-value-parser": "^3.0.0"
-      },
-      "dependencies": {
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-          "dev": true
-        }
-      }
-    },
-    "postcss-discard-comments": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-4.0.2.tgz",
-      "integrity": "sha512-RJutN259iuRf3IW7GZyLM5Sw4GLTOH8FmsXBnv8Ab/Tc2k4SR4qbV4DNbyyY4+Sjo362SyDmW2DQ7lBSChrpkg==",
-      "dev": true,
-      "requires": {
-        "postcss": "^7.0.0"
-      }
-    },
-    "postcss-discard-duplicates": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-4.0.2.tgz",
-      "integrity": "sha512-ZNQfR1gPNAiXZhgENFfEglF93pciw0WxMkJeVmw8eF+JZBbMD7jp6C67GqJAXVZP2BWbOztKfbsdmMp/k8c6oQ==",
-      "dev": true,
-      "requires": {
-        "postcss": "^7.0.0"
-      }
-    },
-    "postcss-discard-empty": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-4.0.1.tgz",
-      "integrity": "sha512-B9miTzbznhDjTfjvipfHoqbWKwd0Mj+/fL5s1QOz06wufguil+Xheo4XpOnc4NqKYBCNqqEzgPv2aPBIJLox0w==",
-      "dev": true,
-      "requires": {
-        "postcss": "^7.0.0"
-      }
-    },
-    "postcss-discard-overridden": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-4.0.1.tgz",
-      "integrity": "sha512-IYY2bEDD7g1XM1IDEsUT4//iEYCxAmP5oDSFMVU/JVvT7gh+l4fmjciLqGgwjdWpQIdb0Che2VX00QObS5+cTg==",
-      "dev": true,
-      "requires": {
-        "postcss": "^7.0.0"
-      }
-    },
-    "postcss-import": {
-      "version": "12.0.1",
-      "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-12.0.1.tgz",
-      "integrity": "sha512-3Gti33dmCjyKBgimqGxL3vcV8w9+bsHwO5UrBawp796+jdardbcFl4RP5w/76BwNL7aGzpKstIfF9I+kdE8pTw==",
-      "dev": true,
-      "requires": {
-        "postcss": "^7.0.1",
-        "postcss-value-parser": "^3.2.3",
-        "read-cache": "^1.0.0",
-        "resolve": "^1.1.7"
-      },
-      "dependencies": {
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-          "dev": true
-        }
-      }
-    },
-    "postcss-load-config": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.2.tgz",
-      "integrity": "sha512-/rDeGV6vMUo3mwJZmeHfEDvwnTKKqQ0S7OHUi/kJvvtx3aWtyWG2/0ZWnzCt2keEclwN6Tf0DST2v9kITdOKYw==",
-      "dev": true,
-      "requires": {
-        "cosmiconfig": "^5.0.0",
-        "import-cwd": "^2.0.0"
+        "nanoid": "^3.3.4",
+        "picocolors": "^1.0.0",
+        "source-map-js": "^1.0.2"
       }
     },
     "postcss-loader": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-3.0.0.tgz",
-      "integrity": "sha512-cLWoDEY5OwHcAjDnkyRQzAXfs2jrKjXpO/HQFcc5b5u/r7aa471wdmChmwfnv7x2u840iat/wi0lQ5nbRgSkUA==",
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.0.2.tgz",
+      "integrity": "sha512-fUJzV/QH7NXUAqV8dWJ9Lg4aTkDCezpTS5HgJ2DvqznexTbSTxgi/dTECvTZ15BwKTtk8G/bqI/QTu2HPd3ZCg==",
       "dev": true,
       "requires": {
-        "loader-utils": "^1.1.0",
-        "postcss": "^7.0.0",
-        "postcss-load-config": "^2.0.0",
-        "schema-utils": "^1.0.0"
+        "cosmiconfig": "^7.0.0",
+        "klona": "^2.0.5",
+        "semver": "^7.3.8"
       },
       "dependencies": {
-        "json5": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
-          "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
+        "semver": {
+          "version": "7.3.8",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz",
+          "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==",
           "dev": true,
           "requires": {
-            "minimist": "^1.2.0"
-          }
-        },
-        "loader-utils": {
-          "version": "1.4.0",
-          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
-          "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
-          "dev": true,
-          "requires": {
-            "big.js": "^5.2.2",
-            "emojis-list": "^3.0.0",
-            "json5": "^1.0.1"
-          }
-        },
-        "schema-utils": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
-          "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
-          "dev": true,
-          "requires": {
-            "ajv": "^6.1.0",
-            "ajv-errors": "^1.0.0",
-            "ajv-keywords": "^3.1.0"
-          }
-        }
-      }
-    },
-    "postcss-merge-longhand": {
-      "version": "4.0.11",
-      "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-4.0.11.tgz",
-      "integrity": "sha512-alx/zmoeXvJjp7L4mxEMjh8lxVlDFX1gqWHzaaQewwMZiVhLo42TEClKaeHbRf6J7j82ZOdTJ808RtN0ZOZwvw==",
-      "dev": true,
-      "requires": {
-        "css-color-names": "0.0.4",
-        "postcss": "^7.0.0",
-        "postcss-value-parser": "^3.0.0",
-        "stylehacks": "^4.0.0"
-      },
-      "dependencies": {
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-          "dev": true
-        }
-      }
-    },
-    "postcss-merge-rules": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-4.0.3.tgz",
-      "integrity": "sha512-U7e3r1SbvYzO0Jr3UT/zKBVgYYyhAz0aitvGIYOYK5CPmkNih+WDSsS5tvPrJ8YMQYlEMvsZIiqmn7HdFUaeEQ==",
-      "dev": true,
-      "requires": {
-        "browserslist": "^4.0.0",
-        "caniuse-api": "^3.0.0",
-        "cssnano-util-same-parent": "^4.0.0",
-        "postcss": "^7.0.0",
-        "postcss-selector-parser": "^3.0.0",
-        "vendors": "^1.0.0"
-      },
-      "dependencies": {
-        "postcss-selector-parser": {
-          "version": "3.1.2",
-          "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz",
-          "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==",
-          "dev": true,
-          "requires": {
-            "dot-prop": "^5.2.0",
-            "indexes-of": "^1.0.1",
-            "uniq": "^1.0.1"
-          }
-        }
-      }
-    },
-    "postcss-minify-font-values": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-4.0.2.tgz",
-      "integrity": "sha512-j85oO6OnRU9zPf04+PZv1LYIYOprWm6IA6zkXkrJXyRveDEuQggG6tvoy8ir8ZwjLxLuGfNkCZEQG7zan+Hbtg==",
-      "dev": true,
-      "requires": {
-        "postcss": "^7.0.0",
-        "postcss-value-parser": "^3.0.0"
-      },
-      "dependencies": {
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-          "dev": true
-        }
-      }
-    },
-    "postcss-minify-gradients": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-4.0.2.tgz",
-      "integrity": "sha512-qKPfwlONdcf/AndP1U8SJ/uzIJtowHlMaSioKzebAXSG4iJthlWC9iSWznQcX4f66gIWX44RSA841HTHj3wK+Q==",
-      "dev": true,
-      "requires": {
-        "cssnano-util-get-arguments": "^4.0.0",
-        "is-color-stop": "^1.0.0",
-        "postcss": "^7.0.0",
-        "postcss-value-parser": "^3.0.0"
-      },
-      "dependencies": {
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-          "dev": true
-        }
-      }
-    },
-    "postcss-minify-params": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-4.0.2.tgz",
-      "integrity": "sha512-G7eWyzEx0xL4/wiBBJxJOz48zAKV2WG3iZOqVhPet/9geefm/Px5uo1fzlHu+DOjT+m0Mmiz3jkQzVHe6wxAWg==",
-      "dev": true,
-      "requires": {
-        "alphanum-sort": "^1.0.0",
-        "browserslist": "^4.0.0",
-        "cssnano-util-get-arguments": "^4.0.0",
-        "postcss": "^7.0.0",
-        "postcss-value-parser": "^3.0.0",
-        "uniqs": "^2.0.0"
-      },
-      "dependencies": {
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-          "dev": true
-        }
-      }
-    },
-    "postcss-minify-selectors": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-4.0.2.tgz",
-      "integrity": "sha512-D5S1iViljXBj9kflQo4YutWnJmwm8VvIsU1GeXJGiG9j8CIg9zs4voPMdQDUmIxetUOh60VilsNzCiAFTOqu3g==",
-      "dev": true,
-      "requires": {
-        "alphanum-sort": "^1.0.0",
-        "has": "^1.0.0",
-        "postcss": "^7.0.0",
-        "postcss-selector-parser": "^3.0.0"
-      },
-      "dependencies": {
-        "postcss-selector-parser": {
-          "version": "3.1.2",
-          "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz",
-          "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==",
-          "dev": true,
-          "requires": {
-            "dot-prop": "^5.2.0",
-            "indexes-of": "^1.0.1",
-            "uniq": "^1.0.1"
+            "lru-cache": "^6.0.0"
           }
         }
       }
     },
     "postcss-modules-extract-imports": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz",
-      "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz",
+      "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==",
       "dev": true,
-      "requires": {
-        "postcss": "^7.0.5"
-      }
+      "requires": {}
     },
     "postcss-modules-local-by-default": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz",
-      "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz",
+      "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==",
       "dev": true,
       "requires": {
-        "icss-utils": "^4.1.1",
-        "postcss": "^7.0.32",
+        "icss-utils": "^5.0.0",
         "postcss-selector-parser": "^6.0.2",
         "postcss-value-parser": "^4.1.0"
       }
     },
     "postcss-modules-scope": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz",
-      "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz",
+      "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==",
       "dev": true,
       "requires": {
-        "postcss": "^7.0.6",
-        "postcss-selector-parser": "^6.0.0"
+        "postcss-selector-parser": "^6.0.4"
       }
     },
     "postcss-modules-values": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz",
-      "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz",
+      "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==",
       "dev": true,
       "requires": {
-        "icss-utils": "^4.0.0",
-        "postcss": "^7.0.6"
-      }
-    },
-    "postcss-normalize-charset": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-4.0.1.tgz",
-      "integrity": "sha512-gMXCrrlWh6G27U0hF3vNvR3w8I1s2wOBILvA87iNXaPvSNo5uZAMYsZG7XjCUf1eVxuPfyL4TJ7++SGZLc9A3g==",
-      "dev": true,
-      "requires": {
-        "postcss": "^7.0.0"
-      }
-    },
-    "postcss-normalize-display-values": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-4.0.2.tgz",
-      "integrity": "sha512-3F2jcsaMW7+VtRMAqf/3m4cPFhPD3EFRgNs18u+k3lTJJlVe7d0YPO+bnwqo2xg8YiRpDXJI2u8A0wqJxMsQuQ==",
-      "dev": true,
-      "requires": {
-        "cssnano-util-get-match": "^4.0.0",
-        "postcss": "^7.0.0",
-        "postcss-value-parser": "^3.0.0"
-      },
-      "dependencies": {
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-          "dev": true
-        }
-      }
-    },
-    "postcss-normalize-positions": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-4.0.2.tgz",
-      "integrity": "sha512-Dlf3/9AxpxE+NF1fJxYDeggi5WwV35MXGFnnoccP/9qDtFrTArZ0D0R+iKcg5WsUd8nUYMIl8yXDCtcrT8JrdA==",
-      "dev": true,
-      "requires": {
-        "cssnano-util-get-arguments": "^4.0.0",
-        "has": "^1.0.0",
-        "postcss": "^7.0.0",
-        "postcss-value-parser": "^3.0.0"
-      },
-      "dependencies": {
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-          "dev": true
-        }
-      }
-    },
-    "postcss-normalize-repeat-style": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-4.0.2.tgz",
-      "integrity": "sha512-qvigdYYMpSuoFs3Is/f5nHdRLJN/ITA7huIoCyqqENJe9PvPmLhNLMu7QTjPdtnVf6OcYYO5SHonx4+fbJE1+Q==",
-      "dev": true,
-      "requires": {
-        "cssnano-util-get-arguments": "^4.0.0",
-        "cssnano-util-get-match": "^4.0.0",
-        "postcss": "^7.0.0",
-        "postcss-value-parser": "^3.0.0"
-      },
-      "dependencies": {
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-          "dev": true
-        }
-      }
-    },
-    "postcss-normalize-string": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-4.0.2.tgz",
-      "integrity": "sha512-RrERod97Dnwqq49WNz8qo66ps0swYZDSb6rM57kN2J+aoyEAJfZ6bMx0sx/F9TIEX0xthPGCmeyiam/jXif0eA==",
-      "dev": true,
-      "requires": {
-        "has": "^1.0.0",
-        "postcss": "^7.0.0",
-        "postcss-value-parser": "^3.0.0"
-      },
-      "dependencies": {
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-          "dev": true
-        }
-      }
-    },
-    "postcss-normalize-timing-functions": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-4.0.2.tgz",
-      "integrity": "sha512-acwJY95edP762e++00Ehq9L4sZCEcOPyaHwoaFOhIwWCDfik6YvqsYNxckee65JHLKzuNSSmAdxwD2Cud1Z54A==",
-      "dev": true,
-      "requires": {
-        "cssnano-util-get-match": "^4.0.0",
-        "postcss": "^7.0.0",
-        "postcss-value-parser": "^3.0.0"
-      },
-      "dependencies": {
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-          "dev": true
-        }
-      }
-    },
-    "postcss-normalize-unicode": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-4.0.1.tgz",
-      "integrity": "sha512-od18Uq2wCYn+vZ/qCOeutvHjB5jm57ToxRaMeNuf0nWVHaP9Hua56QyMF6fs/4FSUnVIw0CBPsU0K4LnBPwYwg==",
-      "dev": true,
-      "requires": {
-        "browserslist": "^4.0.0",
-        "postcss": "^7.0.0",
-        "postcss-value-parser": "^3.0.0"
-      },
-      "dependencies": {
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-          "dev": true
-        }
-      }
-    },
-    "postcss-normalize-url": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-4.0.1.tgz",
-      "integrity": "sha512-p5oVaF4+IHwu7VpMan/SSpmpYxcJMtkGppYf0VbdH5B6hN8YNmVyJLuY9FmLQTzY3fag5ESUUHDqM+heid0UVA==",
-      "dev": true,
-      "requires": {
-        "is-absolute-url": "^2.0.0",
-        "normalize-url": "^3.0.0",
-        "postcss": "^7.0.0",
-        "postcss-value-parser": "^3.0.0"
-      },
-      "dependencies": {
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-          "dev": true
-        }
-      }
-    },
-    "postcss-normalize-whitespace": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-4.0.2.tgz",
-      "integrity": "sha512-tO8QIgrsI3p95r8fyqKV+ufKlSHh9hMJqACqbv2XknufqEDhDvbguXGBBqxw9nsQoXWf0qOqppziKJKHMD4GtA==",
-      "dev": true,
-      "requires": {
-        "postcss": "^7.0.0",
-        "postcss-value-parser": "^3.0.0"
-      },
-      "dependencies": {
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-          "dev": true
-        }
-      }
-    },
-    "postcss-ordered-values": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-4.1.2.tgz",
-      "integrity": "sha512-2fCObh5UanxvSxeXrtLtlwVThBvHn6MQcu4ksNT2tsaV2Fg76R2CV98W7wNSlX+5/pFwEyaDwKLLoEV7uRybAw==",
-      "dev": true,
-      "requires": {
-        "cssnano-util-get-arguments": "^4.0.0",
-        "postcss": "^7.0.0",
-        "postcss-value-parser": "^3.0.0"
-      },
-      "dependencies": {
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-          "dev": true
-        }
-      }
-    },
-    "postcss-reduce-initial": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-4.0.3.tgz",
-      "integrity": "sha512-gKWmR5aUulSjbzOfD9AlJiHCGH6AEVLaM0AV+aSioxUDd16qXP1PCh8d1/BGVvpdWn8k/HiK7n6TjeoXN1F7DA==",
-      "dev": true,
-      "requires": {
-        "browserslist": "^4.0.0",
-        "caniuse-api": "^3.0.0",
-        "has": "^1.0.0",
-        "postcss": "^7.0.0"
-      }
-    },
-    "postcss-reduce-transforms": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-4.0.2.tgz",
-      "integrity": "sha512-EEVig1Q2QJ4ELpJXMZR8Vt5DQx8/mo+dGWSR7vWXqcob2gQLyQGsionYcGKATXvQzMPn6DSN1vTN7yFximdIAg==",
-      "dev": true,
-      "requires": {
-        "cssnano-util-get-match": "^4.0.0",
-        "has": "^1.0.0",
-        "postcss": "^7.0.0",
-        "postcss-value-parser": "^3.0.0"
-      },
-      "dependencies": {
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-          "dev": true
-        }
+        "icss-utils": "^5.0.0"
       }
     },
     "postcss-selector-parser": {
-      "version": "6.0.4",
-      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz",
-      "integrity": "sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==",
+      "version": "6.0.11",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.11.tgz",
+      "integrity": "sha512-zbARubNdogI9j7WY4nQJBiNqQf3sLS3wCP4WfOidu+p28LofJqDH1tcXypGrcmMHhDk2t9wGhCsYe/+szLTy1g==",
       "dev": true,
       "requires": {
         "cssesc": "^3.0.0",
-        "indexes-of": "^1.0.1",
-        "uniq": "^1.0.1",
         "util-deprecate": "^1.0.2"
       }
     },
-    "postcss-svgo": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-4.0.2.tgz",
-      "integrity": "sha512-C6wyjo3VwFm0QgBy+Fu7gCYOkCmgmClghO+pjcxvrcBKtiKt0uCF+hvbMO1fyv5BMImRK90SMb+dwUnfbGd+jw==",
-      "dev": true,
-      "requires": {
-        "is-svg": "^3.0.0",
-        "postcss": "^7.0.0",
-        "postcss-value-parser": "^3.0.0",
-        "svgo": "^1.0.0"
-      },
-      "dependencies": {
-        "postcss-value-parser": {
-          "version": "3.3.1",
-          "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-          "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-          "dev": true
-        }
-      }
-    },
-    "postcss-unique-selectors": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-4.0.1.tgz",
-      "integrity": "sha512-+JanVaryLo9QwZjKrmJgkI4Fn8SBgRO6WXQBJi7KiAVPlmxikB5Jzc4EvXMT2H0/m0RjrVVm9rGNhZddm/8Spg==",
-      "dev": true,
-      "requires": {
-        "alphanum-sort": "^1.0.0",
-        "postcss": "^7.0.0",
-        "uniqs": "^2.0.0"
-      }
-    },
     "postcss-value-parser": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz",
-      "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==",
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+      "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
       "dev": true
     },
-    "prepend-http": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
-      "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
-      "dev": true
-    },
-    "process": {
-      "version": "0.11.10",
-      "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
-      "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
+    "pretty-bytes": {
+      "version": "5.6.0",
+      "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
+      "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==",
       "dev": true
     },
     "process-nextick-args": {
@@ -8847,45 +18443,37 @@
     "promise-retry": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-1.1.1.tgz",
-      "integrity": "sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0=",
+      "integrity": "sha512-StEy2osPr28o17bIW776GtwO6+Q+M9zPiZkYfosciUUMYqjhU/ffwRAH0zN2+uvGyUsn8/YICIHRzLbPacpZGw==",
       "dev": true,
       "requires": {
         "err-code": "^1.0.0",
         "retry": "^0.10.0"
-      },
-      "dependencies": {
-        "retry": {
-          "version": "0.10.1",
-          "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz",
-          "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=",
-          "dev": true
-        }
-      }
-    },
-    "protoduck": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/protoduck/-/protoduck-5.0.1.tgz",
-      "integrity": "sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg==",
-      "dev": true,
-      "requires": {
-        "genfun": "^5.0.0"
       }
     },
     "proxy-addr": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz",
-      "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==",
+      "version": "2.0.7",
+      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+      "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
       "dev": true,
       "requires": {
-        "forwarded": "~0.1.2",
+        "forwarded": "0.2.0",
         "ipaddr.js": "1.9.1"
+      },
+      "dependencies": {
+        "ipaddr.js": {
+          "version": "1.9.1",
+          "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+          "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
+          "dev": true
+        }
       }
     },
     "prr": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
-      "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
-      "dev": true
+      "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==",
+      "dev": true,
+      "optional": true
     },
     "psl": {
       "version": "1.8.0",
@@ -8893,105 +18481,25 @@
       "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==",
       "dev": true
     },
-    "public-encrypt": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
-      "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
-      "dev": true,
-      "requires": {
-        "bn.js": "^4.1.0",
-        "browserify-rsa": "^4.0.0",
-        "create-hash": "^1.1.0",
-        "parse-asn1": "^5.0.0",
-        "randombytes": "^2.0.1",
-        "safe-buffer": "^5.1.2"
-      },
-      "dependencies": {
-        "bn.js": {
-          "version": "4.11.9",
-          "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz",
-          "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==",
-          "dev": true
-        }
-      }
-    },
-    "pump": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
-      "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
-      "dev": true,
-      "requires": {
-        "end-of-stream": "^1.1.0",
-        "once": "^1.3.1"
-      }
-    },
-    "pumpify": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz",
-      "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==",
-      "dev": true,
-      "requires": {
-        "duplexify": "^3.6.0",
-        "inherits": "^2.0.3",
-        "pump": "^2.0.0"
-      },
-      "dependencies": {
-        "pump": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz",
-          "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==",
-          "dev": true,
-          "requires": {
-            "end-of-stream": "^1.1.0",
-            "once": "^1.3.1"
-          }
-        }
-      }
-    },
     "punycode": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
       "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
       "dev": true
     },
-    "q": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
-      "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=",
-      "dev": true
-    },
     "qs": {
-      "version": "6.7.0",
-      "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
-      "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
-      "dev": true
-    },
-    "query-string": {
-      "version": "4.3.4",
-      "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
-      "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
+      "version": "6.11.0",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
+      "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
       "dev": true,
       "requires": {
-        "object-assign": "^4.1.0",
-        "strict-uri-encode": "^1.0.0"
+        "side-channel": "^1.0.4"
       }
     },
-    "querystring": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
-      "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
-      "dev": true
-    },
-    "querystring-es3": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
-      "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",
-      "dev": true
-    },
-    "querystringify": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
-      "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
+    "queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
       "dev": true
     },
     "randombytes": {
@@ -9003,16 +18511,6 @@
         "safe-buffer": "^5.1.0"
       }
     },
-    "randomfill": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
-      "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
-      "dev": true,
-      "requires": {
-        "randombytes": "^2.0.5",
-        "safe-buffer": "^5.1.0"
-      }
-    },
     "range-parser": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@@ -9020,82 +18518,33 @@
       "dev": true
     },
     "raw-body": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
-      "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
+      "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
       "dev": true,
       "requires": {
-        "bytes": "3.1.0",
-        "http-errors": "1.7.2",
+        "bytes": "3.1.2",
+        "http-errors": "2.0.0",
         "iconv-lite": "0.4.24",
         "unpipe": "1.0.0"
       },
       "dependencies": {
         "bytes": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
-          "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
-          "dev": true
-        },
-        "iconv-lite": {
-          "version": "0.4.24",
-          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
-          "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
-          "dev": true,
-          "requires": {
-            "safer-buffer": ">= 2.1.2 < 3"
-          }
-        }
-      }
-    },
-    "raw-loader": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.1.tgz",
-      "integrity": "sha512-baolhQBSi3iNh1cglJjA0mYzga+wePk7vdEX//1dTFd+v4TsQlQE0jitJSNF1OIP82rdYulH7otaVmdlDaJ64A==",
-      "dev": true,
-      "requires": {
-        "loader-utils": "^2.0.0",
-        "schema-utils": "^2.6.5"
-      }
-    },
-    "read-cache": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
-      "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=",
-      "dev": true,
-      "requires": {
-        "pify": "^2.3.0"
-      },
-      "dependencies": {
-        "pify": {
-          "version": "2.3.0",
-          "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-          "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
+          "version": "3.1.2",
+          "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+          "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
           "dev": true
         }
       }
     },
-    "read-package-json": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.1.2.tgz",
-      "integrity": "sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==",
+    "read-package-json-fast": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-1.2.2.tgz",
+      "integrity": "sha512-39DbPJjkltEzfXJXB6D8/Ir3GFOU2YbSKa2HaB/Y3nKrc/zY+0XrALpID6/13ezWyzqvOHrBbR4t4cjQuTdBVQ==",
       "dev": true,
       "requires": {
-        "glob": "^7.1.1",
         "json-parse-even-better-errors": "^2.3.0",
-        "normalize-package-data": "^2.0.0",
-        "npm-normalize-package-bin": "^1.0.0"
-      }
-    },
-    "read-package-tree": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/read-package-tree/-/read-package-tree-5.3.1.tgz",
-      "integrity": "sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw==",
-      "dev": true,
-      "requires": {
-        "read-package-json": "^2.0.0",
-        "readdir-scoped-modules": "^1.0.0",
-        "util-promisify": "^2.1.0"
+        "npm-normalize-package-bin": "^1.0.1"
       }
     },
     "readable-stream": {
@@ -9113,23 +18562,10 @@
         "util-deprecate": "~1.0.1"
       }
     },
-    "readdir-scoped-modules": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz",
-      "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==",
-      "dev": true,
-      "requires": {
-        "debuglog": "^1.0.1",
-        "dezalgo": "^1.0.0",
-        "graceful-fs": "^4.1.2",
-        "once": "^1.3.0"
-      }
-    },
     "readdirp": {
-      "version": "3.5.0",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.5.0.tgz",
-      "integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
-      "dev": true,
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
       "requires": {
         "picomatch": "^2.2.1"
       }
@@ -9137,8 +18573,7 @@
     "reflect-metadata": {
       "version": "0.1.13",
       "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
-      "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==",
-      "dev": true
+      "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg=="
     },
     "regenerate": {
       "version": "1.4.2",
@@ -9147,79 +18582,53 @@
       "dev": true
     },
     "regenerate-unicode-properties": {
-      "version": "8.2.0",
-      "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz",
-      "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==",
+      "version": "10.1.0",
+      "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz",
+      "integrity": "sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ==",
       "dev": true,
       "requires": {
-        "regenerate": "^1.4.0"
+        "regenerate": "^1.4.2"
       }
     },
     "regenerator-runtime": {
-      "version": "0.13.7",
-      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
-      "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==",
+      "version": "0.13.11",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+      "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
       "dev": true
     },
     "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.1",
+      "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.1.tgz",
+      "integrity": "sha512-knzmNAcuyxV+gQCufkYcvOqX/qIIfHLv0u5x79kRxuGojfYVky1f15TzZEu2Avte8QGepvUNTnLskf8E6X6Vyg==",
       "dev": true,
       "requires": {
         "@babel/runtime": "^7.8.4"
       }
     },
-    "regex-not": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
-      "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
-      "dev": true,
-      "requires": {
-        "extend-shallow": "^3.0.2",
-        "safe-regex": "^1.1.0"
-      }
-    },
     "regex-parser": {
       "version": "2.2.11",
       "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz",
       "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==",
       "dev": true
     },
-    "regexp.prototype.flags": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz",
-      "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==",
-      "dev": true,
-      "requires": {
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.17.0-next.1"
-      }
-    },
     "regexpu-core": {
-      "version": "4.7.1",
-      "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz",
-      "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==",
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.0.tgz",
+      "integrity": "sha512-ZdhUQlng0RoscyW7jADnUZ25F5eVtHdMyXSb2PiwafvteRAOJUjFoUPEYZSIfP99fBIs3maLIRfpEddT78wAAQ==",
       "dev": true,
       "requires": {
-        "regenerate": "^1.4.0",
-        "regenerate-unicode-properties": "^8.2.0",
-        "regjsgen": "^0.5.1",
-        "regjsparser": "^0.6.4",
-        "unicode-match-property-ecmascript": "^1.0.4",
-        "unicode-match-property-value-ecmascript": "^1.2.0"
+        "@babel/regjsgen": "^0.8.0",
+        "regenerate": "^1.4.2",
+        "regenerate-unicode-properties": "^10.1.0",
+        "regjsparser": "^0.9.1",
+        "unicode-match-property-ecmascript": "^2.0.0",
+        "unicode-match-property-value-ecmascript": "^2.1.0"
       }
     },
-    "regjsgen": {
-      "version": "0.5.2",
-      "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz",
-      "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==",
-      "dev": true
-    },
     "regjsparser": {
-      "version": "0.6.4",
-      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz",
-      "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==",
+      "version": "0.9.1",
+      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz",
+      "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==",
       "dev": true,
       "requires": {
         "jsesc": "~0.5.0"
@@ -9228,29 +18637,11 @@
         "jsesc": {
           "version": "0.5.0",
           "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
-          "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
+          "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==",
           "dev": true
         }
       }
     },
-    "remove-trailing-separator": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
-      "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
-      "dev": true
-    },
-    "repeat-element": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
-      "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
-      "dev": true
-    },
-    "repeat-string": {
-      "version": "1.6.1",
-      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
-      "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
-      "dev": true
-    },
     "request": {
       "version": "2.88.2",
       "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz",
@@ -9280,9 +18671,9 @@
       },
       "dependencies": {
         "qs": {
-          "version": "6.5.2",
-          "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
-          "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
+          "version": "6.5.3",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz",
+          "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==",
           "dev": true
         }
       }
@@ -9292,100 +18683,55 @@
       "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
       "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
     },
-    "require-main-filename": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
-      "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
+    "require-from-string": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+      "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+      "dev": true
     },
     "requires-port": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
-      "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
+      "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
       "dev": true
     },
     "resolve": {
-      "version": "1.18.1",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz",
-      "integrity": "sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA==",
+      "version": "1.19.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz",
+      "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==",
       "requires": {
-        "is-core-module": "^2.0.0",
+        "is-core-module": "^2.1.0",
         "path-parse": "^1.0.6"
       }
     },
-    "resolve-cwd": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz",
-      "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=",
-      "dev": true,
-      "requires": {
-        "resolve-from": "^3.0.0"
-      }
-    },
     "resolve-from": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz",
-      "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=",
-      "dev": true
-    },
-    "resolve-url": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
-      "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz",
+      "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==",
       "dev": true
     },
     "resolve-url-loader": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.2.tgz",
-      "integrity": "sha512-QEb4A76c8Mi7I3xNKXlRKQSlLBwjUV/ULFMP+G7n3/7tJZ8MG5wsZ3ucxP1Jz8Vevn6fnJsxDx9cIls+utGzPQ==",
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz",
+      "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==",
       "dev": true,
       "requires": {
-        "adjust-sourcemap-loader": "3.0.0",
-        "camelcase": "5.3.1",
-        "compose-function": "3.0.3",
-        "convert-source-map": "1.7.0",
-        "es6-iterator": "2.0.3",
-        "loader-utils": "1.2.3",
-        "postcss": "7.0.21",
-        "rework": "1.0.1",
-        "rework-visit": "1.0.0",
+        "adjust-sourcemap-loader": "^4.0.0",
+        "convert-source-map": "^1.7.0",
+        "loader-utils": "^2.0.0",
+        "postcss": "^8.2.14",
         "source-map": "0.6.1"
       },
       "dependencies": {
-        "emojis-list": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
-          "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
-          "dev": true
-        },
-        "json5": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
-          "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
-          "dev": true,
-          "requires": {
-            "minimist": "^1.2.0"
-          }
-        },
         "loader-utils": {
-          "version": "1.2.3",
-          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz",
-          "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==",
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
+          "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==",
           "dev": true,
           "requires": {
             "big.js": "^5.2.2",
-            "emojis-list": "^2.0.0",
-            "json5": "^1.0.1"
-          }
-        },
-        "postcss": {
-          "version": "7.0.21",
-          "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.21.tgz",
-          "integrity": "sha512-uIFtJElxJo29QC753JzhidoAhvp/e/Exezkdhfmt8AymWT6/5B7W1WmponYWkHk2eg6sONyTch0A3nkMPun3SQ==",
-          "dev": true,
-          "requires": {
-            "chalk": "^2.4.2",
-            "source-map": "^0.6.1",
-            "supports-color": "^6.1.0"
+            "emojis-list": "^3.0.0",
+            "json5": "^2.1.2"
           }
         },
         "source-map": {
@@ -9393,15 +18739,6 @@
           "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
           "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
           "dev": true
-        },
-        "supports-color": {
-          "version": "6.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
-          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^3.0.0"
-          }
         }
       }
     },
@@ -9415,16 +18752,10 @@
         "signal-exit": "^3.0.2"
       }
     },
-    "ret": {
-      "version": "0.1.15",
-      "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
-      "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
-      "dev": true
-    },
     "retry": {
-      "version": "0.12.0",
-      "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
-      "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=",
+      "version": "0.10.1",
+      "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz",
+      "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=",
       "dev": true
     },
     "reusify": {
@@ -9433,42 +18764,6 @@
       "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
       "dev": true
     },
-    "rework": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/rework/-/rework-1.0.1.tgz",
-      "integrity": "sha1-MIBqhBNCtUUQqkEQhQzUhTQUSqc=",
-      "dev": true,
-      "requires": {
-        "convert-source-map": "^0.3.3",
-        "css": "^2.0.0"
-      },
-      "dependencies": {
-        "convert-source-map": {
-          "version": "0.3.5",
-          "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz",
-          "integrity": "sha1-8dgClQr33SYxof6+BZZVDIarMZA=",
-          "dev": true
-        }
-      }
-    },
-    "rework-visit": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/rework-visit/-/rework-visit-1.0.0.tgz",
-      "integrity": "sha1-mUWygD8hni96ygCtuLyfZA+ELJo=",
-      "dev": true
-    },
-    "rgb-regex": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz",
-      "integrity": "sha1-wODWiC3w4jviVKR16O3UGRX+rrE=",
-      "dev": true
-    },
-    "rgba-regex": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz",
-      "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM=",
-      "dev": true
-    },
     "rimraf": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -9494,25 +18789,6 @@
         }
       }
     },
-    "ripemd160": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
-      "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
-      "dev": true,
-      "requires": {
-        "hash-base": "^3.0.0",
-        "inherits": "^2.0.1"
-      }
-    },
-    "rollup": {
-      "version": "2.26.5",
-      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.26.5.tgz",
-      "integrity": "sha512-rCyFG3ZtQdnn9YwfuAVH0l/Om34BdO5lwCA0W6Hq+bNB21dVEBbCRxhaHOmu1G7OBFDWytbzAC104u7rxHwGjA==",
-      "dev": true,
-      "requires": {
-        "fsevents": "~2.1.2"
-      }
-    },
     "run-async": {
       "version": "2.4.1",
       "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz",
@@ -9520,18 +18796,12 @@
       "dev": true
     },
     "run-parallel": {
-      "version": "1.1.10",
-      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.10.tgz",
-      "integrity": "sha512-zb/1OuZ6flOlH6tQyMPUrE3x3Ulxjlo9WIVXR4yVYi4H9UXQaeIsPbLn2R3O3vQCnDKkAl2qHiuocKKX4Tz/Sw==",
-      "dev": true
-    },
-    "run-queue": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz",
-      "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
       "dev": true,
       "requires": {
-        "aproba": "^1.1.1"
+        "queue-microtask": "^1.2.2"
       }
     },
     "rxjs": {
@@ -9540,6 +18810,13 @@
       "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==",
       "requires": {
         "tslib": "^1.9.0"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "1.14.1",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+          "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+        }
       }
     },
     "rxjs-compat": {
@@ -9552,15 +18829,6 @@
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
       "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
     },
-    "safe-regex": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
-      "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
-      "dev": true,
-      "requires": {
-        "ret": "~0.1.10"
-      }
-    },
     "safer-buffer": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
@@ -9568,65 +18836,87 @@
       "dev": true
     },
     "sass": {
-      "version": "1.26.10",
-      "resolved": "https://registry.npmjs.org/sass/-/sass-1.26.10.tgz",
-      "integrity": "sha512-bzN0uvmzfsTvjz0qwccN1sPm2HxxpNI/Xa+7PlUEMS+nQvbyuEK7Y0qFqxlPHhiNHb1Ze8WQJtU31olMObkAMw==",
+      "version": "1.58.1",
+      "resolved": "https://registry.npmjs.org/sass/-/sass-1.58.1.tgz",
+      "integrity": "sha512-bnINi6nPXbP1XNRaranMFEBZWUfdW/AF16Ql5+ypRxfTvCRTTKrLsMIakyDcayUt2t/RZotmL4kgJwNH5xO+bg==",
       "dev": true,
       "requires": {
-        "chokidar": ">=2.0.0 <4.0.0"
+        "chokidar": ">=3.0.0 <4.0.0",
+        "immutable": "^4.0.0",
+        "source-map-js": ">=0.6.2 <2.0.0"
       }
     },
     "sass-loader": {
-      "version": "10.0.1",
-      "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-10.0.1.tgz",
-      "integrity": "sha512-b2PSldKVTS3JcFPHSrEXh3BeAfR7XknGiGCAO5aHruR3Pf3kqLP3Gb2ypXLglRrAzgZkloNxLZ7GXEGDX0hBUQ==",
+      "version": "13.2.0",
+      "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.2.0.tgz",
+      "integrity": "sha512-JWEp48djQA4nbZxmgC02/Wh0eroSUutulROUusYJO9P9zltRbNN80JCBHqRGzjd4cmZCa/r88xgfkjGD0TXsHg==",
       "dev": true,
       "requires": {
-        "klona": "^2.0.3",
-        "loader-utils": "^2.0.0",
-        "neo-async": "^2.6.2",
-        "schema-utils": "^2.7.0",
-        "semver": "^7.3.2"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "7.3.2",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz",
-          "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
-          "dev": true
-        }
+        "klona": "^2.0.4",
+        "neo-async": "^2.6.2"
       }
     },
     "sax": {
       "version": "1.2.4",
       "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
       "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
-      "dev": true
+      "dev": true,
+      "optional": true
     },
     "schema-utils": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz",
-      "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz",
+      "integrity": "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg==",
       "dev": true,
       "requires": {
-        "@types/json-schema": "^7.0.5",
-        "ajv": "^6.12.4",
-        "ajv-keywords": "^3.5.2"
+        "@types/json-schema": "^7.0.9",
+        "ajv": "^8.8.0",
+        "ajv-formats": "^2.1.1",
+        "ajv-keywords": "^5.0.0"
+      },
+      "dependencies": {
+        "ajv": {
+          "version": "8.12.0",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+          "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+          "dev": true,
+          "requires": {
+            "fast-deep-equal": "^3.1.1",
+            "json-schema-traverse": "^1.0.0",
+            "require-from-string": "^2.0.2",
+            "uri-js": "^4.2.2"
+          }
+        },
+        "ajv-keywords": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+          "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+          "dev": true,
+          "requires": {
+            "fast-deep-equal": "^3.1.3"
+          }
+        },
+        "json-schema-traverse": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+          "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+          "dev": true
+        }
       }
     },
     "select-hose": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz",
-      "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=",
+      "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==",
       "dev": true
     },
     "selfsigned": {
-      "version": "1.10.8",
-      "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz",
-      "integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==",
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.1.1.tgz",
+      "integrity": "sha512-GSL3aowiF7wa/WtSFwnUrludWFoNhftq8bUkH9pkzjpN2XSPOAYEgg6e0sS9s0rZwgJzJiQRPU18A6clnoW5wQ==",
       "dev": true,
       "requires": {
-        "node-forge": "^0.10.0"
+        "node-forge": "^1"
       }
     },
     "semver": {
@@ -9653,24 +18943,24 @@
       }
     },
     "send": {
-      "version": "0.17.1",
-      "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
-      "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
+      "version": "0.18.0",
+      "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
+      "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
       "dev": true,
       "requires": {
         "debug": "2.6.9",
-        "depd": "~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.7.2",
+        "http-errors": "2.0.0",
         "mime": "1.6.0",
-        "ms": "2.1.1",
-        "on-finished": "~2.3.0",
+        "ms": "2.1.3",
+        "on-finished": "2.4.1",
         "range-parser": "~1.2.1",
-        "statuses": "~1.5.0"
+        "statuses": "2.0.1"
       },
       "dependencies": {
         "debug": {
@@ -9685,23 +18975,29 @@
             "ms": {
               "version": "2.0.0",
               "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-              "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+              "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
               "dev": true
             }
           }
         },
+        "depd": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+          "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
+          "dev": true
+        },
         "ms": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
-          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
+          "version": "2.1.3",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+          "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
           "dev": true
         }
       }
     },
     "serialize-javascript": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
-      "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
+      "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
       "dev": true,
       "requires": {
         "randombytes": "^2.1.0"
@@ -9710,7 +19006,7 @@
     "serve-index": {
       "version": "1.9.1",
       "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
-      "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=",
+      "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==",
       "dev": true,
       "requires": {
         "accepts": "~1.3.4",
@@ -9734,7 +19030,7 @@
         "http-errors": {
           "version": "1.6.3",
           "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
-          "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
+          "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==",
           "dev": true,
           "requires": {
             "depd": "~1.1.2",
@@ -9746,13 +19042,13 @@
         "inherits": {
           "version": "2.0.3",
           "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+          "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
           "dev": true
         },
         "ms": {
           "version": "2.0.0",
           "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
           "dev": true
         },
         "setprototypeof": {
@@ -9760,377 +19056,180 @@
           "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
           "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
           "dev": true
+        },
+        "statuses": {
+          "version": "1.5.0",
+          "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+          "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==",
+          "dev": true
         }
       }
     },
     "serve-static": {
-      "version": "1.14.1",
-      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
-      "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
+      "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
       "dev": true,
       "requires": {
         "encodeurl": "~1.0.2",
         "escape-html": "~1.0.3",
         "parseurl": "~1.3.3",
-        "send": "0.17.1"
+        "send": "0.18.0"
       }
     },
     "set-blocking": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
-      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
-    },
-    "set-value": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
-      "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
-      "dev": true,
-      "requires": {
-        "extend-shallow": "^2.0.1",
-        "is-extendable": "^0.1.1",
-        "is-plain-object": "^2.0.3",
-        "split-string": "^3.0.1"
-      },
-      "dependencies": {
-        "extend-shallow": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-          "dev": true,
-          "requires": {
-            "is-extendable": "^0.1.0"
-          }
-        }
-      }
-    },
-    "setimmediate": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
-      "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
+      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
       "dev": true
     },
     "setprototypeof": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
-      "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
+      "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
       "dev": true
     },
-    "sha.js": {
-      "version": "2.4.11",
-      "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
-      "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+    "shallow-clone": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
+      "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
       "dev": true,
       "requires": {
-        "inherits": "^2.0.1",
-        "safe-buffer": "^5.0.1"
+        "kind-of": "^6.0.2"
       }
     },
     "shebang-command": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
-      "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
+      "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
       "dev": true,
       "requires": {
-        "shebang-regex": "^1.0.0"
+        "shebang-regex": "^3.0.0"
       }
     },
     "shebang-regex": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
-      "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
+      "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
       "dev": true
     },
+    "side-channel": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+      "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+      "dev": true,
+      "requires": {
+        "call-bind": "^1.0.0",
+        "get-intrinsic": "^1.0.2",
+        "object-inspect": "^1.9.0"
+      }
+    },
     "signal-exit": {
       "version": "3.0.3",
       "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
       "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
       "dev": true
     },
-    "simple-swizzle": {
-      "version": "0.2.2",
-      "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
-      "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
+    "sirv": {
+      "version": "1.0.19",
+      "resolved": "https://registry.npmjs.org/sirv/-/sirv-1.0.19.tgz",
+      "integrity": "sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ==",
       "dev": true,
       "requires": {
-        "is-arrayish": "^0.3.1"
-      },
-      "dependencies": {
-        "is-arrayish": {
-          "version": "0.3.2",
-          "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
-          "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
-          "dev": true
-        }
+        "@polka/url": "^1.0.0-next.20",
+        "mrmime": "^1.0.0",
+        "totalist": "^1.0.0"
       }
     },
     "slash": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
-      "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz",
+      "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==",
       "dev": true
     },
     "smart-buffer": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz",
-      "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==",
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
+      "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
       "dev": true
     },
-    "snapdragon": {
-      "version": "0.8.2",
-      "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
-      "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
-      "dev": true,
-      "requires": {
-        "base": "^0.11.1",
-        "debug": "^2.2.0",
-        "define-property": "^0.2.5",
-        "extend-shallow": "^2.0.1",
-        "map-cache": "^0.2.2",
-        "source-map": "^0.5.6",
-        "source-map-resolve": "^0.5.0",
-        "use": "^3.1.0"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "2.6.9",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-          "dev": true,
-          "requires": {
-            "ms": "2.0.0"
-          }
-        },
-        "define-property": {
-          "version": "0.2.5",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^0.1.0"
-          }
-        },
-        "extend-shallow": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-          "dev": true,
-          "requires": {
-            "is-extendable": "^0.1.0"
-          }
-        },
-        "ms": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
-          "dev": true
-        }
-      }
-    },
-    "snapdragon-node": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
-      "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
-      "dev": true,
-      "requires": {
-        "define-property": "^1.0.0",
-        "isobject": "^3.0.0",
-        "snapdragon-util": "^3.0.1"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
-          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^1.0.0"
-          }
-        },
-        "is-accessor-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
-          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-data-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
-          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-descriptor": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
-          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
-          "dev": true,
-          "requires": {
-            "is-accessor-descriptor": "^1.0.0",
-            "is-data-descriptor": "^1.0.0",
-            "kind-of": "^6.0.2"
-          }
-        }
-      }
-    },
-    "snapdragon-util": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
-      "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
-      "dev": true,
-      "requires": {
-        "kind-of": "^3.2.0"
-      },
-      "dependencies": {
-        "kind-of": {
-          "version": "3.2.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-          "dev": true,
-          "requires": {
-            "is-buffer": "^1.1.5"
-          }
-        }
-      }
-    },
     "sockjs": {
-      "version": "0.3.20",
-      "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.20.tgz",
-      "integrity": "sha512-SpmVOVpdq0DJc0qArhF3E5xsxvaiqGNb73XfgBpK1y3UD5gs8DSo8aCTsuT5pX8rssdc2NDIzANwP9eCAiSdTA==",
+      "version": "0.3.24",
+      "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
+      "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==",
       "dev": true,
       "requires": {
-        "faye-websocket": "^0.10.0",
-        "uuid": "^3.4.0",
-        "websocket-driver": "0.6.5"
-      }
-    },
-    "sockjs-client": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.4.0.tgz",
-      "integrity": "sha512-5zaLyO8/nri5cua0VtOrFXBPK1jbL4+1cebT/mmKA1E1ZXOvJrII75bPu0l0k843G/+iAbhEqzyKr0w/eCCj7g==",
-      "dev": true,
-      "requires": {
-        "debug": "^3.2.5",
-        "eventsource": "^1.0.7",
-        "faye-websocket": "~0.11.1",
-        "inherits": "^2.0.3",
-        "json3": "^3.3.2",
-        "url-parse": "^1.4.3"
+        "faye-websocket": "^0.11.3",
+        "uuid": "^8.3.2",
+        "websocket-driver": "^0.7.4"
       },
       "dependencies": {
-        "debug": {
-          "version": "3.2.6",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
-          "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "faye-websocket": {
-          "version": "0.11.3",
-          "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz",
-          "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==",
-          "dev": true,
-          "requires": {
-            "websocket-driver": ">=0.5.1"
-          }
+        "uuid": {
+          "version": "8.3.2",
+          "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+          "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+          "dev": true
         }
       }
     },
     "socks": {
-      "version": "2.3.3",
-      "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz",
-      "integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==",
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz",
+      "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==",
       "dev": true,
       "requires": {
-        "ip": "1.1.5",
-        "smart-buffer": "^4.1.0"
+        "ip": "^1.1.5",
+        "smart-buffer": "^4.2.0"
       }
     },
     "socks-proxy-agent": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz",
-      "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==",
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz",
+      "integrity": "sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ==",
       "dev": true,
       "requires": {
-        "agent-base": "~4.2.1",
-        "socks": "~2.3.2"
-      },
-      "dependencies": {
-        "agent-base": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz",
-          "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==",
-          "dev": true,
-          "requires": {
-            "es6-promisify": "^5.0.0"
-          }
-        }
+        "agent-base": "^6.0.2",
+        "debug": "4",
+        "socks": "^2.3.3"
       }
     },
-    "sort-keys": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
-      "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
-      "dev": true,
-      "requires": {
-        "is-plain-obj": "^1.0.0"
-      }
-    },
-    "source-list-map": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
-      "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==",
-      "dev": true
-    },
     "source-map": {
       "version": "0.5.7",
       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
       "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
     },
-    "source-map-loader": {
+    "source-map-js": {
       "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-1.0.2.tgz",
-      "integrity": "sha512-oX8d6ndRjN+tVyjj6PlXSyFPhDdVAPsZA30nD3/II8g4uOv8fCz0DMn5sy8KtVbDfKQxOpGwGJnK3xIW3tauDw==",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+      "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+      "dev": true
+    },
+    "source-map-loader": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-4.0.1.tgz",
+      "integrity": "sha512-oqXpzDIByKONVY8g1NUPOTQhe0UTU5bWUl32GSkqK2LjJj0HmwTMVKxcUip0RgAYhY1mqgOxjbQM48a0mmeNfA==",
       "dev": true,
       "requires": {
-        "data-urls": "^2.0.0",
-        "iconv-lite": "^0.6.2",
-        "loader-utils": "^2.0.0",
-        "schema-utils": "^2.7.0",
-        "source-map": "^0.6.1"
+        "abab": "^2.0.6",
+        "iconv-lite": "^0.6.3",
+        "source-map-js": "^1.0.2"
       },
       "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
+        "iconv-lite": {
+          "version": "0.6.3",
+          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+          "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+          "dev": true,
+          "requires": {
+            "safer-buffer": ">= 2.1.2 < 3.0.0"
+          }
         }
       }
     },
-    "source-map-resolve": {
-      "version": "0.5.3",
-      "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz",
-      "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==",
-      "dev": true,
-      "requires": {
-        "atob": "^2.1.2",
-        "decode-uri-component": "^0.2.0",
-        "resolve-url": "^0.2.1",
-        "source-map-url": "^0.4.0",
-        "urix": "^0.1.0"
-      }
-    },
     "source-map-support": {
-      "version": "0.5.19",
-      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
-      "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
+      "version": "0.5.21",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
+      "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
       "dev": true,
       "requires": {
         "buffer-from": "^1.0.0",
@@ -10145,49 +19244,10 @@
         }
       }
     },
-    "source-map-url": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
-      "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
-      "dev": true
-    },
     "sourcemap-codec": {
       "version": "1.4.8",
       "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
-      "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
-      "dev": true
-    },
-    "spdx-correct": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz",
-      "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==",
-      "dev": true,
-      "requires": {
-        "spdx-expression-parse": "^3.0.0",
-        "spdx-license-ids": "^3.0.0"
-      }
-    },
-    "spdx-exceptions": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
-      "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
-      "dev": true
-    },
-    "spdx-expression-parse": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
-      "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
-      "dev": true,
-      "requires": {
-        "spdx-exceptions": "^2.1.0",
-        "spdx-license-ids": "^3.0.0"
-      }
-    },
-    "spdx-license-ids": {
-      "version": "3.0.6",
-      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz",
-      "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==",
-      "dev": true
+      "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="
     },
     "spdy": {
       "version": "4.0.2",
@@ -10217,9 +19277,9 @@
       },
       "dependencies": {
         "readable-stream": {
-          "version": "3.6.0",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
-          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "version": "3.6.2",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+          "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
           "dev": true,
           "requires": {
             "inherits": "^2.0.3",
@@ -10229,24 +19289,6 @@
         }
       }
     },
-    "speed-measure-webpack-plugin": {
-      "version": "1.3.3",
-      "resolved": "https://registry.npmjs.org/speed-measure-webpack-plugin/-/speed-measure-webpack-plugin-1.3.3.tgz",
-      "integrity": "sha512-2ljD4Ch/rz2zG3HsLsnPfp23osuPBS0qPuz9sGpkNXTN1Ic4M+W9xB8l8rS8ob2cO4b1L+WTJw/0AJwWYVgcxQ==",
-      "dev": true,
-      "requires": {
-        "chalk": "^2.0.1"
-      }
-    },
-    "split-string": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
-      "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
-      "dev": true,
-      "requires": {
-        "extend-shallow": "^3.0.0"
-      }
-    },
     "sprintf-js": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
@@ -10279,84 +19321,21 @@
         "minipass": "^3.1.1"
       }
     },
-    "stable": {
-      "version": "0.1.8",
-      "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz",
-      "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==",
-      "dev": true
-    },
-    "static-extend": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
-      "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
-      "dev": true,
-      "requires": {
-        "define-property": "^0.2.5",
-        "object-copy": "^0.1.0"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "0.2.5",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^0.1.0"
-          }
-        }
-      }
-    },
     "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==",
       "dev": true
     },
-    "stream-browserify": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
-      "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==",
+    "string_decoder": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
       "dev": true,
       "requires": {
-        "inherits": "~2.0.1",
-        "readable-stream": "^2.0.2"
+        "safe-buffer": "~5.1.0"
       }
     },
-    "stream-each": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz",
-      "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==",
-      "dev": true,
-      "requires": {
-        "end-of-stream": "^1.1.0",
-        "stream-shift": "^1.0.0"
-      }
-    },
-    "stream-http": {
-      "version": "2.8.3",
-      "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz",
-      "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==",
-      "dev": true,
-      "requires": {
-        "builtin-status-codes": "^3.0.0",
-        "inherits": "^2.0.1",
-        "readable-stream": "^2.3.6",
-        "to-arraybuffer": "^1.0.0",
-        "xtend": "^4.0.0"
-      }
-    },
-    "stream-shift": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz",
-      "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==",
-      "dev": true
-    },
-    "strict-uri-encode": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
-      "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
-      "dev": true
-    },
     "string-width": {
       "version": "4.2.0",
       "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
@@ -10367,79 +19346,6 @@
         "strip-ansi": "^6.0.0"
       }
     },
-    "string.prototype.trimend": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.2.tgz",
-      "integrity": "sha512-8oAG/hi14Z4nOVP0z6mdiVZ/wqjDtWSLygMigTzAb+7aPEDTleeFf+WrF+alzecxIRkckkJVn+dTlwzJXORATw==",
-      "dev": true,
-      "requires": {
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.18.0-next.1"
-      },
-      "dependencies": {
-        "es-abstract": {
-          "version": "1.18.0-next.1",
-          "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz",
-          "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==",
-          "dev": true,
-          "requires": {
-            "es-to-primitive": "^1.2.1",
-            "function-bind": "^1.1.1",
-            "has": "^1.0.3",
-            "has-symbols": "^1.0.1",
-            "is-callable": "^1.2.2",
-            "is-negative-zero": "^2.0.0",
-            "is-regex": "^1.1.1",
-            "object-inspect": "^1.8.0",
-            "object-keys": "^1.1.1",
-            "object.assign": "^4.1.1",
-            "string.prototype.trimend": "^1.0.1",
-            "string.prototype.trimstart": "^1.0.1"
-          }
-        }
-      }
-    },
-    "string.prototype.trimstart": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.2.tgz",
-      "integrity": "sha512-7F6CdBTl5zyu30BJFdzSTlSlLPwODC23Od+iLoVH8X6+3fvDPPuBVVj9iaB1GOsSTSIgVfsfm27R2FGrAPznWg==",
-      "dev": true,
-      "requires": {
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.18.0-next.1"
-      },
-      "dependencies": {
-        "es-abstract": {
-          "version": "1.18.0-next.1",
-          "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.1.tgz",
-          "integrity": "sha512-I4UGspA0wpZXWENrdA0uHbnhte683t3qT/1VFH9aX2dA5PPSf6QW5HHXf5HImaqPmjXaVeVk4RGWnaylmV7uAA==",
-          "dev": true,
-          "requires": {
-            "es-to-primitive": "^1.2.1",
-            "function-bind": "^1.1.1",
-            "has": "^1.0.3",
-            "has-symbols": "^1.0.1",
-            "is-callable": "^1.2.2",
-            "is-negative-zero": "^2.0.0",
-            "is-regex": "^1.1.1",
-            "object-inspect": "^1.8.0",
-            "object-keys": "^1.1.1",
-            "object.assign": "^4.1.1",
-            "string.prototype.trimend": "^1.0.1",
-            "string.prototype.trimstart": "^1.0.1"
-          }
-        }
-      }
-    },
-    "string_decoder": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "~5.1.0"
-      }
-    },
     "strip-ansi": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
@@ -10448,144 +19354,12 @@
         "ansi-regex": "^5.0.0"
       }
     },
-    "strip-eof": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
-      "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
+    "strip-final-newline": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
+      "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
       "dev": true
     },
-    "style-loader": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.2.1.tgz",
-      "integrity": "sha512-ByHSTQvHLkWE9Ir5+lGbVOXhxX10fbprhLvdg96wedFZb4NDekDPxVKv5Fwmio+QcMlkkNfuK+5W1peQ5CUhZg==",
-      "dev": true,
-      "requires": {
-        "loader-utils": "^2.0.0",
-        "schema-utils": "^2.6.6"
-      }
-    },
-    "stylehacks": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-4.0.3.tgz",
-      "integrity": "sha512-7GlLk9JwlElY4Y6a/rmbH2MhVlTyVmiJd1PfTCqFaIBEGMYNsrO/v3SeGTdhBThLg4Z+NbOk/qFMwCa+J+3p/g==",
-      "dev": true,
-      "requires": {
-        "browserslist": "^4.0.0",
-        "postcss": "^7.0.0",
-        "postcss-selector-parser": "^3.0.0"
-      },
-      "dependencies": {
-        "postcss-selector-parser": {
-          "version": "3.1.2",
-          "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.2.tgz",
-          "integrity": "sha512-h7fJ/5uWuRVyOtkO45pnt1Ih40CEleeyCHzipqAZO2e5H20g25Y48uYnFUiShvY4rZWNJ/Bib/KVPmanaCtOhA==",
-          "dev": true,
-          "requires": {
-            "dot-prop": "^5.2.0",
-            "indexes-of": "^1.0.1",
-            "uniq": "^1.0.1"
-          }
-        }
-      }
-    },
-    "stylus": {
-      "version": "0.54.8",
-      "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.8.tgz",
-      "integrity": "sha512-vr54Or4BZ7pJafo2mpf0ZcwA74rpuYCZbxrHBsH8kbcXOwSfvBFwsRfpGO5OD5fhG5HDCFW737PKaawI7OqEAg==",
-      "dev": true,
-      "requires": {
-        "css-parse": "~2.0.0",
-        "debug": "~3.1.0",
-        "glob": "^7.1.6",
-        "mkdirp": "~1.0.4",
-        "safer-buffer": "^2.1.2",
-        "sax": "~1.2.4",
-        "semver": "^6.3.0",
-        "source-map": "^0.7.3"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
-          "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
-          "dev": true,
-          "requires": {
-            "ms": "2.0.0"
-          }
-        },
-        "glob": {
-          "version": "7.1.6",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
-        "mkdirp": {
-          "version": "1.0.4",
-          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
-          "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
-          "dev": true
-        },
-        "ms": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
-          "dev": true
-        },
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.7.3",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
-          "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
-          "dev": true
-        }
-      }
-    },
-    "stylus-loader": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-3.0.2.tgz",
-      "integrity": "sha512-+VomPdZ6a0razP+zinir61yZgpw2NfljeSsdUF5kJuEzlo3khXhY19Fn6l8QQz1GRJGtMCo8nG5C04ePyV7SUA==",
-      "dev": true,
-      "requires": {
-        "loader-utils": "^1.0.2",
-        "lodash.clonedeep": "^4.5.0",
-        "when": "~3.6.x"
-      },
-      "dependencies": {
-        "json5": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
-          "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
-          "dev": true,
-          "requires": {
-            "minimist": "^1.2.0"
-          }
-        },
-        "loader-utils": {
-          "version": "1.4.0",
-          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
-          "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
-          "dev": true,
-          "requires": {
-            "big.js": "^5.2.2",
-            "emojis-list": "^3.0.0",
-            "json5": "^1.0.1"
-          }
-        }
-      }
-    },
     "supports-color": {
       "version": "5.5.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -10594,42 +19368,21 @@
         "has-flag": "^3.0.0"
       }
     },
-    "svgo": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz",
-      "integrity": "sha512-yhy/sQYxR5BkC98CY7o31VGsg014AKLEPxdfhora76l36hD9Rdy5NZA/Ocn6yayNPgSamYdtX2rFJdcv07AYVw==",
-      "dev": true,
-      "requires": {
-        "chalk": "^2.4.1",
-        "coa": "^2.0.2",
-        "css-select": "^2.0.0",
-        "css-select-base-adapter": "^0.1.1",
-        "css-tree": "1.0.0-alpha.37",
-        "csso": "^4.0.2",
-        "js-yaml": "^3.13.1",
-        "mkdirp": "~0.5.1",
-        "object.values": "^1.1.0",
-        "sax": "~1.2.4",
-        "stable": "^0.1.8",
-        "unquote": "~1.1.1",
-        "util.promisify": "~1.0.0"
-      }
-    },
     "swagger-ui-dist": {
-      "version": "4.1.3",
-      "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.1.3.tgz",
-      "integrity": "sha512-WvfPSfAAMlE/sKS6YkW47nX/hA7StmhYnAHc6wWCXNL0oclwLj6UXv0hQCkLnDgvebi0MEV40SJJpVjKUgH1IQ=="
+      "version": "3.52.5",
+      "resolved": "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-3.52.5.tgz",
+      "integrity": "sha512-8z18eX8G/jbTXYzyNIaobrnD7PSN7yU/YkSasMmajrXtw0FGS64XjrKn5v37d36qmU3o1xLeuYnktshRr7uIFw=="
     },
     "symbol-observable": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz",
-      "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==",
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-3.0.0.tgz",
+      "integrity": "sha512-6tDOXSHiVjuCaasQSWTmHUWn4PuG7qa3+1WT031yTc/swT7+rLiw3GOrFxaH1E3lLP09dH3bVuVDf2gK5rxG3Q==",
       "dev": true
     },
     "tapable": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz",
-      "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
+      "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
       "dev": true
     },
     "tar": {
@@ -10655,95 +19408,88 @@
       }
     },
     "terser": {
-      "version": "5.3.0",
-      "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.0.tgz",
-      "integrity": "sha512-XTT3D3AwxC54KywJijmY2mxZ8nJiEjBHVYzq8l9OaYuRFWeQNBwvipuzzYEP4e+/AVcd1hqG/CqgsdIRyT45Fg==",
+      "version": "5.16.3",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.3.tgz",
+      "integrity": "sha512-v8wWLaS/xt3nE9dgKEWhNUFP6q4kngO5B8eYFUuebsu7Dw/UNAnpUod6UHo04jSSkv8TzKHjZDSd7EXdDQAl8Q==",
       "dev": true,
       "requires": {
+        "@jridgewell/source-map": "^0.3.2",
+        "acorn": "^8.5.0",
         "commander": "^2.20.0",
-        "source-map": "~0.6.1",
-        "source-map-support": "~0.5.12"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
+        "source-map-support": "~0.5.20"
       }
     },
     "terser-webpack-plugin": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-4.1.0.tgz",
-      "integrity": "sha512-0ZWDPIP8BtEDZdChbufcXUigOYk6dOX/P/X0hWxqDDcVAQLb8Yy/0FAaemSfax3PAA67+DJR778oz8qVbmy4hA==",
+      "version": "5.3.6",
+      "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.6.tgz",
+      "integrity": "sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==",
       "dev": true,
       "requires": {
-        "cacache": "^15.0.5",
-        "find-cache-dir": "^3.3.1",
-        "jest-worker": "^26.3.0",
-        "p-limit": "^3.0.2",
-        "schema-utils": "^2.6.6",
-        "serialize-javascript": "^4.0.0",
-        "source-map": "^0.6.1",
-        "terser": "^5.0.0",
-        "webpack-sources": "^1.4.3"
+        "@jridgewell/trace-mapping": "^0.3.14",
+        "jest-worker": "^27.4.5",
+        "schema-utils": "^3.1.1",
+        "serialize-javascript": "^6.0.0",
+        "terser": "^5.14.1"
       },
       "dependencies": {
-        "p-limit": {
-          "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz",
-          "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==",
+        "schema-utils": {
+          "version": "3.1.1",
+          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
+          "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
           "dev": true,
           "requires": {
-            "p-try": "^2.0.0"
+            "@types/json-schema": "^7.0.8",
+            "ajv": "^6.12.5",
+            "ajv-keywords": "^3.5.2"
           }
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
         }
       }
     },
+    "test-exclude": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz",
+      "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==",
+      "dev": true,
+      "requires": {
+        "@istanbuljs/schema": "^0.1.2",
+        "glob": "^7.1.4",
+        "minimatch": "^3.0.4"
+      },
+      "dependencies": {
+        "glob": {
+          "version": "7.2.3",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+          "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+          "dev": true,
+          "requires": {
+            "fs.realpath": "^1.0.0",
+            "inflight": "^1.0.4",
+            "inherits": "2",
+            "minimatch": "^3.1.1",
+            "once": "^1.3.0",
+            "path-is-absolute": "^1.0.0"
+          }
+        }
+      }
+    },
+    "text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
+      "dev": true
+    },
     "through": {
       "version": "2.3.8",
       "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
       "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
       "dev": true
     },
-    "through2": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
-      "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
-      "dev": true,
-      "requires": {
-        "readable-stream": "~2.3.6",
-        "xtend": "~4.0.1"
-      }
-    },
     "thunky": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz",
       "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==",
       "dev": true
     },
-    "timers-browserify": {
-      "version": "2.0.12",
-      "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz",
-      "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==",
-      "dev": true,
-      "requires": {
-        "setimmediate": "^1.0.4"
-      }
-    },
-    "timsort": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
-      "integrity": "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q=",
-      "dev": true
-    },
     "tmp": {
       "version": "0.0.33",
       "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -10753,62 +19499,29 @@
         "os-tmpdir": "~1.0.2"
       }
     },
-    "to-arraybuffer": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
-      "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
-      "dev": true
-    },
     "to-fast-properties": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
       "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
     },
-    "to-object-path": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
-      "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
-      "dev": true,
-      "requires": {
-        "kind-of": "^3.0.2"
-      },
-      "dependencies": {
-        "kind-of": {
-          "version": "3.2.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-          "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-          "dev": true,
-          "requires": {
-            "is-buffer": "^1.1.5"
-          }
-        }
-      }
-    },
-    "to-regex": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
-      "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
-      "dev": true,
-      "requires": {
-        "define-property": "^2.0.2",
-        "extend-shallow": "^3.0.2",
-        "regex-not": "^1.0.2",
-        "safe-regex": "^1.1.0"
-      }
-    },
     "to-regex-range": {
       "version": "5.0.1",
       "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
       "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
-      "dev": true,
       "requires": {
         "is-number": "^7.0.0"
       }
     },
     "toidentifier": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
-      "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
+      "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
+      "dev": true
+    },
+    "totalist": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz",
+      "integrity": "sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==",
       "dev": true
     },
     "tough-cookie": {
@@ -10821,27 +19534,12 @@
         "punycode": "^2.1.1"
       }
     },
-    "tr46": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz",
-      "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==",
-      "dev": true,
-      "requires": {
-        "punycode": "^2.1.1"
-      }
-    },
     "tree-kill": {
       "version": "1.2.2",
       "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
       "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
       "dev": true
     },
-    "tryer": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz",
-      "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==",
-      "dev": true
-    },
     "ts-node": {
       "version": "8.4.1",
       "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-8.4.1.tgz",
@@ -10855,21 +19553,15 @@
         "yn": "^3.0.0"
       }
     },
-    "ts-pnp": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz",
-      "integrity": "sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==",
-      "dev": true
-    },
     "tslib": {
-      "version": "1.14.1",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
-      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
+      "integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
     },
     "tslint": {
-      "version": "5.20.1",
-      "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz",
-      "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==",
+      "version": "6.1.3",
+      "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz",
+      "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==",
       "dev": true,
       "requires": {
         "@babel/code-frame": "^7.0.0",
@@ -10880,11 +19572,19 @@
         "glob": "^7.1.1",
         "js-yaml": "^3.13.1",
         "minimatch": "^3.0.4",
-        "mkdirp": "^0.5.1",
+        "mkdirp": "^0.5.3",
         "resolve": "^1.3.2",
         "semver": "^5.3.0",
-        "tslib": "^1.8.0",
+        "tslib": "^1.13.0",
         "tsutils": "^2.29.0"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "1.14.1",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+          "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+          "dev": true
+        }
       }
     },
     "tsutils": {
@@ -10894,14 +19594,16 @@
       "dev": true,
       "requires": {
         "tslib": "^1.8.1"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "1.14.1",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+          "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+          "dev": true
+        }
       }
     },
-    "tty-browserify": {
-      "version": "0.0.0",
-      "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
-      "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=",
-      "dev": true
-    },
     "tunnel-agent": {
       "version": "0.6.0",
       "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
@@ -10917,12 +19619,6 @@
       "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
       "dev": true
     },
-    "type": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
-      "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==",
-      "dev": true
-    },
     "type-fest": {
       "version": "0.11.0",
       "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz",
@@ -10939,68 +19635,43 @@
         "mime-types": "~2.1.24"
       }
     },
-    "typedarray": {
-      "version": "0.0.6",
-      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
-      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
+    "typed-assert": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz",
+      "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==",
       "dev": true
     },
     "typescript": {
-      "version": "3.9.7",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz",
-      "integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==",
-      "dev": true
+      "version": "4.1.6",
+      "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.6.tgz",
+      "integrity": "sha512-pxnwLxeb/Z5SP80JDRzVjh58KsM6jZHRAOtTpS7sXLS4ogXNKC9ANxHHZqLLeVHZN35jCtI4JdmLLbLiC1kBow=="
     },
     "unicode-canonical-property-names-ecmascript": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
-      "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz",
+      "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==",
       "dev": true
     },
     "unicode-match-property-ecmascript": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz",
-      "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz",
+      "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==",
       "dev": true,
       "requires": {
-        "unicode-canonical-property-names-ecmascript": "^1.0.4",
-        "unicode-property-aliases-ecmascript": "^1.0.4"
+        "unicode-canonical-property-names-ecmascript": "^2.0.0",
+        "unicode-property-aliases-ecmascript": "^2.0.0"
       }
     },
     "unicode-match-property-value-ecmascript": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz",
-      "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz",
+      "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==",
       "dev": true
     },
     "unicode-property-aliases-ecmascript": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz",
-      "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==",
-      "dev": true
-    },
-    "union-value": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
-      "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
-      "dev": true,
-      "requires": {
-        "arr-union": "^3.1.0",
-        "get-value": "^2.0.6",
-        "is-extendable": "^0.1.1",
-        "set-value": "^2.0.1"
-      }
-    },
-    "uniq": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
-      "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=",
-      "dev": true
-    },
-    "uniqs": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz",
-      "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz",
+      "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==",
       "dev": true
     },
     "unique-filename": {
@@ -11035,67 +19706,23 @@
     "universalify": {
       "version": "0.1.2",
       "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
-      "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
-      "dev": true
+      "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
     },
     "unpipe": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
-      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
+      "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
       "dev": true
     },
-    "unquote": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz",
-      "integrity": "sha1-j97XMk7G6IoP+LkF58CYzcCG1UQ=",
-      "dev": true
-    },
-    "unset-value": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
-      "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
-      "dev": true,
+    "update-browserslist-db": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
+      "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
       "requires": {
-        "has-value": "^0.3.1",
-        "isobject": "^3.0.0"
-      },
-      "dependencies": {
-        "has-value": {
-          "version": "0.3.1",
-          "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
-          "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
-          "dev": true,
-          "requires": {
-            "get-value": "^2.0.3",
-            "has-values": "^0.1.4",
-            "isobject": "^2.0.0"
-          },
-          "dependencies": {
-            "isobject": {
-              "version": "2.1.0",
-              "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
-              "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
-              "dev": true,
-              "requires": {
-                "isarray": "1.0.0"
-              }
-            }
-          }
-        },
-        "has-values": {
-          "version": "0.1.4",
-          "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
-          "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
-          "dev": true
-        }
+        "escalade": "^3.1.1",
+        "picocolors": "^1.0.0"
       }
     },
-    "upath": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
-      "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
-      "dev": true
-    },
     "uri-js": {
       "version": "4.4.0",
       "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz",
@@ -11105,94 +19732,16 @@
         "punycode": "^2.1.0"
       }
     },
-    "urix": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
-      "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
-      "dev": true
-    },
-    "url": {
-      "version": "0.11.0",
-      "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
-      "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
-      "dev": true,
-      "requires": {
-        "punycode": "1.3.2",
-        "querystring": "0.2.0"
-      },
-      "dependencies": {
-        "punycode": {
-          "version": "1.3.2",
-          "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
-          "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
-          "dev": true
-        }
-      }
-    },
-    "url-parse": {
-      "version": "1.5.10",
-      "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
-      "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
-      "dev": true,
-      "requires": {
-        "querystringify": "^2.1.1",
-        "requires-port": "^1.0.0"
-      }
-    },
-    "use": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
-      "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
-      "dev": true
-    },
-    "util": {
-      "version": "0.11.1",
-      "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
-      "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==",
-      "dev": true,
-      "requires": {
-        "inherits": "2.0.3"
-      },
-      "dependencies": {
-        "inherits": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
-          "dev": true
-        }
-      }
-    },
     "util-deprecate": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
       "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
       "dev": true
     },
-    "util-promisify": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/util-promisify/-/util-promisify-2.1.0.tgz",
-      "integrity": "sha1-PCI2R2xNMsX/PEcAKt18E7moKlM=",
-      "dev": true,
-      "requires": {
-        "object.getownpropertydescriptors": "^2.0.3"
-      }
-    },
-    "util.promisify": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.1.tgz",
-      "integrity": "sha512-g9JpC/3He3bm38zsLupWryXHoEcS22YHthuPQSJdMy6KNrzIRzWqcsHzD/WUnqe45whVou4VIsPew37DoXWNrA==",
-      "dev": true,
-      "requires": {
-        "define-properties": "^1.1.3",
-        "es-abstract": "^1.17.2",
-        "has-symbols": "^1.0.1",
-        "object.getownpropertydescriptors": "^2.1.0"
-      }
-    },
     "utils-merge": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
-      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
+      "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
       "dev": true
     },
     "uuid": {
@@ -11201,16 +19750,6 @@
       "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
       "dev": true
     },
-    "validate-npm-package-license": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
-      "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
-      "dev": true,
-      "requires": {
-        "spdx-correct": "^3.0.0",
-        "spdx-expression-parse": "^3.0.0"
-      }
-    },
     "validate-npm-package-name": {
       "version": "3.0.0",
       "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz",
@@ -11223,13 +19762,7 @@
     "vary": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
-      "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
-      "dev": true
-    },
-    "vendors": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz",
-      "integrity": "sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w==",
+      "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
       "dev": true
     },
     "verror": {
@@ -11243,248 +19776,14 @@
         "extsprintf": "^1.2.0"
       }
     },
-    "vm-browserify": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
-      "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
-      "dev": true
-    },
     "watchpack": {
-      "version": "1.7.4",
-      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.4.tgz",
-      "integrity": "sha512-aWAgTW4MoSJzZPAicljkO1hsi1oKj/RRq/OJQh2PKI2UKL04c2Bs+MBOB+BBABHTXJpf9mCwHN7ANCvYsvY2sg==",
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
+      "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==",
       "dev": true,
       "requires": {
-        "chokidar": "^3.4.1",
-        "graceful-fs": "^4.1.2",
-        "neo-async": "^2.5.0",
-        "watchpack-chokidar2": "^2.0.0"
-      }
-    },
-    "watchpack-chokidar2": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.0.tgz",
-      "integrity": "sha512-9TyfOyN/zLUbA288wZ8IsMZ+6cbzvsNyEzSBp6e/zkifi6xxbl8SmQ/CxQq32k8NNqrdVEVUVSEf56L4rQ/ZxA==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "chokidar": "^2.1.8"
-      },
-      "dependencies": {
-        "anymatch": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
-          "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "micromatch": "^3.1.4",
-            "normalize-path": "^2.1.1"
-          },
-          "dependencies": {
-            "normalize-path": {
-              "version": "2.1.1",
-              "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
-              "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
-              "dev": true,
-              "optional": true,
-              "requires": {
-                "remove-trailing-separator": "^1.0.1"
-              }
-            }
-          }
-        },
-        "binary-extensions": {
-          "version": "1.13.1",
-          "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
-          "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
-          "dev": true,
-          "optional": true
-        },
-        "braces": {
-          "version": "2.3.2",
-          "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
-          "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "arr-flatten": "^1.1.0",
-            "array-unique": "^0.3.2",
-            "extend-shallow": "^2.0.1",
-            "fill-range": "^4.0.0",
-            "isobject": "^3.0.1",
-            "repeat-element": "^1.1.2",
-            "snapdragon": "^0.8.1",
-            "snapdragon-node": "^2.0.1",
-            "split-string": "^3.0.2",
-            "to-regex": "^3.0.1"
-          },
-          "dependencies": {
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "optional": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            }
-          }
-        },
-        "chokidar": {
-          "version": "2.1.8",
-          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
-          "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "anymatch": "^2.0.0",
-            "async-each": "^1.0.1",
-            "braces": "^2.3.2",
-            "fsevents": "^1.2.7",
-            "glob-parent": "^3.1.0",
-            "inherits": "^2.0.3",
-            "is-binary-path": "^1.0.0",
-            "is-glob": "^4.0.0",
-            "normalize-path": "^3.0.0",
-            "path-is-absolute": "^1.0.0",
-            "readdirp": "^2.2.1",
-            "upath": "^1.1.1"
-          }
-        },
-        "fill-range": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
-          "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "extend-shallow": "^2.0.1",
-            "is-number": "^3.0.0",
-            "repeat-string": "^1.6.1",
-            "to-regex-range": "^2.1.0"
-          },
-          "dependencies": {
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "optional": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            }
-          }
-        },
-        "fsevents": {
-          "version": "1.2.13",
-          "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
-          "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
-          "dev": true,
-          "optional": true
-        },
-        "glob-parent": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
-          "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "is-glob": "^3.1.0",
-            "path-dirname": "^1.0.0"
-          },
-          "dependencies": {
-            "is-glob": {
-              "version": "3.1.0",
-              "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
-              "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
-              "dev": true,
-              "optional": true,
-              "requires": {
-                "is-extglob": "^2.1.0"
-              }
-            }
-          }
-        },
-        "is-binary-path": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
-          "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "binary-extensions": "^1.0.0"
-          }
-        },
-        "is-number": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
-          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "kind-of": "^3.0.2"
-          },
-          "dependencies": {
-            "kind-of": {
-              "version": "3.2.2",
-              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-              "dev": true,
-              "optional": true,
-              "requires": {
-                "is-buffer": "^1.1.5"
-              }
-            }
-          }
-        },
-        "micromatch": {
-          "version": "3.1.10",
-          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
-          "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "arr-diff": "^4.0.0",
-            "array-unique": "^0.3.2",
-            "braces": "^2.3.1",
-            "define-property": "^2.0.2",
-            "extend-shallow": "^3.0.2",
-            "extglob": "^2.0.4",
-            "fragment-cache": "^0.2.1",
-            "kind-of": "^6.0.2",
-            "nanomatch": "^1.2.9",
-            "object.pick": "^1.3.0",
-            "regex-not": "^1.0.0",
-            "snapdragon": "^0.8.1",
-            "to-regex": "^3.0.2"
-          }
-        },
-        "readdirp": {
-          "version": "2.2.1",
-          "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
-          "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "graceful-fs": "^4.1.11",
-            "micromatch": "^3.1.10",
-            "readable-stream": "^2.0.2"
-          }
-        },
-        "to-regex-range": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
-          "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "is-number": "^3.0.0",
-            "repeat-string": "^1.6.1"
-          }
-        }
+        "glob-to-regexp": "^0.4.1",
+        "graceful-fs": "^4.1.2"
       }
     },
     "wbuf": {
@@ -11510,874 +19809,241 @@
       "resolved": "https://registry.npmjs.org/web-animations-js/-/web-animations-js-2.3.2.tgz",
       "integrity": "sha512-TOMFWtQdxzjWp8qx4DAraTWTsdhxVSiWa6NkPFSaPtZ1diKUxTn4yTix73A1euG1WbSOMMPcY51cnjTIHrGtDA=="
     },
-    "webidl-conversions": {
-      "version": "6.1.0",
-      "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",
-      "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==",
-      "dev": true
-    },
     "webpack": {
-      "version": "4.44.1",
-      "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.44.1.tgz",
-      "integrity": "sha512-4UOGAohv/VGUNQJstzEywwNxqX417FnjZgZJpJQegddzPmTvph37eBIRbRTfdySXzVtJXLJfbMN3mMYhM6GdmQ==",
+      "version": "5.76.1",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz",
+      "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==",
       "dev": true,
       "requires": {
-        "@webassemblyjs/ast": "1.9.0",
-        "@webassemblyjs/helper-module-context": "1.9.0",
-        "@webassemblyjs/wasm-edit": "1.9.0",
-        "@webassemblyjs/wasm-parser": "1.9.0",
-        "acorn": "^6.4.1",
-        "ajv": "^6.10.2",
-        "ajv-keywords": "^3.4.1",
+        "@types/eslint-scope": "^3.7.3",
+        "@types/estree": "^0.0.51",
+        "@webassemblyjs/ast": "1.11.1",
+        "@webassemblyjs/wasm-edit": "1.11.1",
+        "@webassemblyjs/wasm-parser": "1.11.1",
+        "acorn": "^8.7.1",
+        "acorn-import-assertions": "^1.7.6",
+        "browserslist": "^4.14.5",
         "chrome-trace-event": "^1.0.2",
-        "enhanced-resolve": "^4.3.0",
-        "eslint-scope": "^4.0.3",
-        "json-parse-better-errors": "^1.0.2",
-        "loader-runner": "^2.4.0",
-        "loader-utils": "^1.2.3",
-        "memory-fs": "^0.4.1",
-        "micromatch": "^3.1.10",
-        "mkdirp": "^0.5.3",
-        "neo-async": "^2.6.1",
-        "node-libs-browser": "^2.2.1",
-        "schema-utils": "^1.0.0",
-        "tapable": "^1.1.3",
-        "terser-webpack-plugin": "^1.4.3",
-        "watchpack": "^1.7.4",
-        "webpack-sources": "^1.4.1"
+        "enhanced-resolve": "^5.10.0",
+        "es-module-lexer": "^0.9.0",
+        "eslint-scope": "5.1.1",
+        "events": "^3.2.0",
+        "glob-to-regexp": "^0.4.1",
+        "graceful-fs": "^4.2.9",
+        "json-parse-even-better-errors": "^2.3.1",
+        "loader-runner": "^4.2.0",
+        "mime-types": "^2.1.27",
+        "neo-async": "^2.6.2",
+        "schema-utils": "^3.1.0",
+        "tapable": "^2.1.1",
+        "terser-webpack-plugin": "^5.1.3",
+        "watchpack": "^2.4.0",
+        "webpack-sources": "^3.2.3"
       },
       "dependencies": {
-        "braces": {
-          "version": "2.3.2",
-          "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
-          "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
-          "dev": true,
-          "requires": {
-            "arr-flatten": "^1.1.0",
-            "array-unique": "^0.3.2",
-            "extend-shallow": "^2.0.1",
-            "fill-range": "^4.0.0",
-            "isobject": "^3.0.1",
-            "repeat-element": "^1.1.2",
-            "snapdragon": "^0.8.1",
-            "snapdragon-node": "^2.0.1",
-            "split-string": "^3.0.2",
-            "to-regex": "^3.0.1"
-          },
-          "dependencies": {
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            }
-          }
-        },
-        "cacache": {
-          "version": "12.0.4",
-          "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz",
-          "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==",
-          "dev": true,
-          "requires": {
-            "bluebird": "^3.5.5",
-            "chownr": "^1.1.1",
-            "figgy-pudding": "^3.5.1",
-            "glob": "^7.1.4",
-            "graceful-fs": "^4.1.15",
-            "infer-owner": "^1.0.3",
-            "lru-cache": "^5.1.1",
-            "mississippi": "^3.0.0",
-            "mkdirp": "^0.5.1",
-            "move-concurrently": "^1.0.1",
-            "promise-inflight": "^1.0.1",
-            "rimraf": "^2.6.3",
-            "ssri": "^6.0.1",
-            "unique-filename": "^1.1.1",
-            "y18n": "^4.0.0"
-          }
-        },
-        "chownr": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
-          "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==",
-          "dev": true
-        },
-        "fill-range": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
-          "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
-          "dev": true,
-          "requires": {
-            "extend-shallow": "^2.0.1",
-            "is-number": "^3.0.0",
-            "repeat-string": "^1.6.1",
-            "to-regex-range": "^2.1.0"
-          },
-          "dependencies": {
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            }
-          }
-        },
-        "find-cache-dir": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz",
-          "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==",
-          "dev": true,
-          "requires": {
-            "commondir": "^1.0.1",
-            "make-dir": "^2.0.0",
-            "pkg-dir": "^3.0.0"
-          }
-        },
-        "glob": {
-          "version": "7.1.6",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
-          "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
-          "dev": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
-        "is-number": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
-          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
-          "dev": true,
-          "requires": {
-            "kind-of": "^3.0.2"
-          },
-          "dependencies": {
-            "kind-of": {
-              "version": "3.2.2",
-              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-              "dev": true,
-              "requires": {
-                "is-buffer": "^1.1.5"
-              }
-            }
-          }
-        },
-        "is-wsl": {
-          "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz",
-          "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=",
-          "dev": true
-        },
-        "json5": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
-          "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
-          "dev": true,
-          "requires": {
-            "minimist": "^1.2.0"
-          }
-        },
-        "loader-utils": {
-          "version": "1.4.0",
-          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
-          "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
-          "dev": true,
-          "requires": {
-            "big.js": "^5.2.2",
-            "emojis-list": "^3.0.0",
-            "json5": "^1.0.1"
-          }
-        },
-        "lru-cache": {
-          "version": "5.1.1",
-          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
-          "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
-          "dev": true,
-          "requires": {
-            "yallist": "^3.0.2"
-          }
-        },
-        "memory-fs": {
-          "version": "0.4.1",
-          "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
-          "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=",
-          "dev": true,
-          "requires": {
-            "errno": "^0.1.3",
-            "readable-stream": "^2.0.1"
-          }
-        },
-        "micromatch": {
-          "version": "3.1.10",
-          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
-          "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
-          "dev": true,
-          "requires": {
-            "arr-diff": "^4.0.0",
-            "array-unique": "^0.3.2",
-            "braces": "^2.3.1",
-            "define-property": "^2.0.2",
-            "extend-shallow": "^3.0.2",
-            "extglob": "^2.0.4",
-            "fragment-cache": "^0.2.1",
-            "kind-of": "^6.0.2",
-            "nanomatch": "^1.2.9",
-            "object.pick": "^1.3.0",
-            "regex-not": "^1.0.0",
-            "snapdragon": "^0.8.1",
-            "to-regex": "^3.0.2"
-          }
-        },
-        "rimraf": {
-          "version": "2.7.1",
-          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
-          "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
-          "dev": true,
-          "requires": {
-            "glob": "^7.1.3"
-          }
-        },
         "schema-utils": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
-          "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
-          "dev": true,
-          "requires": {
-            "ajv": "^6.1.0",
-            "ajv-errors": "^1.0.0",
-            "ajv-keywords": "^3.1.0"
-          }
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        },
-        "ssri": {
-          "version": "6.0.2",
-          "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz",
-          "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==",
-          "dev": true,
-          "requires": {
-            "figgy-pudding": "^3.5.1"
-          }
-        },
-        "terser": {
-          "version": "4.8.0",
-          "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
-          "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==",
-          "dev": true,
-          "requires": {
-            "commander": "^2.20.0",
-            "source-map": "~0.6.1",
-            "source-map-support": "~0.5.12"
-          }
-        },
-        "terser-webpack-plugin": {
-          "version": "1.4.5",
-          "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz",
-          "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==",
-          "dev": true,
-          "requires": {
-            "cacache": "^12.0.2",
-            "find-cache-dir": "^2.1.0",
-            "is-wsl": "^1.1.0",
-            "schema-utils": "^1.0.0",
-            "serialize-javascript": "^4.0.0",
-            "source-map": "^0.6.1",
-            "terser": "^4.1.2",
-            "webpack-sources": "^1.4.0",
-            "worker-farm": "^1.7.0"
-          }
-        },
-        "to-regex-range": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
-          "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
-          "dev": true,
-          "requires": {
-            "is-number": "^3.0.0",
-            "repeat-string": "^1.6.1"
-          }
-        },
-        "yallist": {
           "version": "3.1.1",
-          "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
-          "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==",
-          "dev": true
+          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
+          "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
+          "dev": true,
+          "requires": {
+            "@types/json-schema": "^7.0.8",
+            "ajv": "^6.12.5",
+            "ajv-keywords": "^3.5.2"
+          }
         }
       }
     },
     "webpack-bundle-analyzer": {
-      "version": "3.9.0",
-      "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.9.0.tgz",
-      "integrity": "sha512-Ob8amZfCm3rMB1ScjQVlbYYUEJyEjdEtQ92jqiFUYt5VkEeO2v5UMbv49P/gnmCZm3A6yaFQzCBvpZqN4MUsdA==",
+      "version": "4.7.0",
+      "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz",
+      "integrity": "sha512-j9b8ynpJS4K+zfO5GGwsAcQX4ZHpWV+yRiHDiL+bE0XHJ8NiPYLTNVQdlFYWxtpg9lfAQNlwJg16J9AJtFSXRg==",
       "dev": true,
       "requires": {
-        "acorn": "^7.1.1",
-        "acorn-walk": "^7.1.1",
-        "bfj": "^6.1.1",
-        "chalk": "^2.4.1",
-        "commander": "^2.18.0",
-        "ejs": "^2.6.1",
-        "express": "^4.16.3",
-        "filesize": "^3.6.1",
-        "gzip-size": "^5.0.0",
-        "lodash": "^4.17.19",
-        "mkdirp": "^0.5.1",
-        "opener": "^1.5.1",
-        "ws": "^6.0.0"
+        "acorn": "^8.0.4",
+        "acorn-walk": "^8.0.0",
+        "chalk": "^4.1.0",
+        "commander": "^7.2.0",
+        "gzip-size": "^6.0.0",
+        "lodash": "^4.17.20",
+        "opener": "^1.5.2",
+        "sirv": "^1.0.7",
+        "ws": "^7.3.1"
       },
       "dependencies": {
-        "acorn": {
-          "version": "7.4.1",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
-          "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+        "ansi-styles": {
+          "version": "4.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+          "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+          "dev": true,
+          "requires": {
+            "color-convert": "^2.0.1"
+          }
+        },
+        "chalk": {
+          "version": "4.1.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+          "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "^4.1.0",
+            "supports-color": "^7.1.0"
+          }
+        },
+        "color-convert": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+          "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+          "dev": true,
+          "requires": {
+            "color-name": "~1.1.4"
+          }
+        },
+        "color-name": {
+          "version": "1.1.4",
+          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+          "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
           "dev": true
+        },
+        "commander": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
+          "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        },
+        "ws": {
+          "version": "7.5.9",
+          "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz",
+          "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==",
+          "dev": true,
+          "requires": {}
         }
       }
     },
     "webpack-dev-middleware": {
-      "version": "3.7.2",
-      "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz",
-      "integrity": "sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==",
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.0.1.tgz",
+      "integrity": "sha512-PZPZ6jFinmqVPJZbisfggDiC+2EeGZ1ZByyMP5sOFJcPPWSexalISz+cvm+j+oYPT7FIJyxT76esjnw9DhE5sw==",
       "dev": true,
       "requires": {
-        "memory-fs": "^0.4.1",
-        "mime": "^2.4.4",
-        "mkdirp": "^0.5.1",
+        "colorette": "^2.0.10",
+        "memfs": "^3.4.12",
+        "mime-types": "^2.1.31",
         "range-parser": "^1.2.1",
-        "webpack-log": "^2.0.0"
-      },
-      "dependencies": {
-        "memory-fs": {
-          "version": "0.4.1",
-          "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
-          "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=",
-          "dev": true,
-          "requires": {
-            "errno": "^0.1.3",
-            "readable-stream": "^2.0.1"
-          }
-        },
-        "mime": {
-          "version": "2.4.6",
-          "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz",
-          "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==",
-          "dev": true
-        }
+        "schema-utils": "^4.0.0"
       }
     },
     "webpack-dev-server": {
-      "version": "3.11.0",
-      "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.0.tgz",
-      "integrity": "sha512-PUxZ+oSTxogFQgkTtFndEtJIPNmml7ExwufBZ9L2/Xyyd5PnOL5UreWe5ZT7IU25DSdykL9p1MLQzmLh2ljSeg==",
+      "version": "4.11.1",
+      "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz",
+      "integrity": "sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==",
       "dev": true,
       "requires": {
-        "ansi-html": "0.0.7",
-        "bonjour": "^3.5.0",
-        "chokidar": "^2.1.8",
+        "@types/bonjour": "^3.5.9",
+        "@types/connect-history-api-fallback": "^1.3.5",
+        "@types/express": "^4.17.13",
+        "@types/serve-index": "^1.9.1",
+        "@types/serve-static": "^1.13.10",
+        "@types/sockjs": "^0.3.33",
+        "@types/ws": "^8.5.1",
+        "ansi-html-community": "^0.0.8",
+        "bonjour-service": "^1.0.11",
+        "chokidar": "^3.5.3",
+        "colorette": "^2.0.10",
         "compression": "^1.7.4",
-        "connect-history-api-fallback": "^1.6.0",
-        "debug": "^4.1.1",
-        "del": "^4.1.1",
-        "express": "^4.17.1",
-        "html-entities": "^1.3.1",
-        "http-proxy-middleware": "0.19.1",
-        "import-local": "^2.0.0",
-        "internal-ip": "^4.3.0",
-        "ip": "^1.1.5",
-        "is-absolute-url": "^3.0.3",
-        "killable": "^1.0.1",
-        "loglevel": "^1.6.8",
-        "opn": "^5.5.0",
-        "p-retry": "^3.0.1",
-        "portfinder": "^1.0.26",
-        "schema-utils": "^1.0.0",
-        "selfsigned": "^1.10.7",
-        "semver": "^6.3.0",
+        "connect-history-api-fallback": "^2.0.0",
+        "default-gateway": "^6.0.3",
+        "express": "^4.17.3",
+        "graceful-fs": "^4.2.6",
+        "html-entities": "^2.3.2",
+        "http-proxy-middleware": "^2.0.3",
+        "ipaddr.js": "^2.0.1",
+        "open": "^8.0.9",
+        "p-retry": "^4.5.0",
+        "rimraf": "^3.0.2",
+        "schema-utils": "^4.0.0",
+        "selfsigned": "^2.1.1",
         "serve-index": "^1.9.1",
-        "sockjs": "0.3.20",
-        "sockjs-client": "1.4.0",
+        "sockjs": "^0.3.24",
         "spdy": "^4.0.2",
-        "strip-ansi": "^3.0.1",
-        "supports-color": "^6.1.0",
-        "url": "^0.11.0",
-        "webpack-dev-middleware": "^3.7.2",
-        "webpack-log": "^2.0.0",
-        "ws": "^6.2.1",
-        "yargs": "^13.3.2"
+        "webpack-dev-middleware": "^5.3.1",
+        "ws": "^8.4.2"
       },
       "dependencies": {
-        "ansi-regex": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
-          "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
-          "dev": true
-        },
-        "anymatch": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
-          "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
+        "open": {
+          "version": "8.4.2",
+          "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
+          "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
           "dev": true,
           "requires": {
-            "micromatch": "^3.1.4",
-            "normalize-path": "^2.1.1"
-          },
-          "dependencies": {
-            "normalize-path": {
-              "version": "2.1.1",
-              "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
-              "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
-              "dev": true,
-              "requires": {
-                "remove-trailing-separator": "^1.0.1"
-              }
-            }
+            "define-lazy-prop": "^2.0.0",
+            "is-docker": "^2.1.1",
+            "is-wsl": "^2.2.0"
           }
         },
-        "binary-extensions": {
-          "version": "1.13.1",
-          "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
-          "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
-          "dev": true
-        },
-        "braces": {
-          "version": "2.3.2",
-          "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
-          "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
+        "webpack-dev-middleware": {
+          "version": "5.3.3",
+          "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz",
+          "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==",
           "dev": true,
           "requires": {
-            "arr-flatten": "^1.1.0",
-            "array-unique": "^0.3.2",
-            "extend-shallow": "^2.0.1",
-            "fill-range": "^4.0.0",
-            "isobject": "^3.0.1",
-            "repeat-element": "^1.1.2",
-            "snapdragon": "^0.8.1",
-            "snapdragon-node": "^2.0.1",
-            "split-string": "^3.0.2",
-            "to-regex": "^3.0.1"
-          },
-          "dependencies": {
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            }
-          }
-        },
-        "chokidar": {
-          "version": "2.1.8",
-          "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
-          "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
-          "dev": true,
-          "requires": {
-            "anymatch": "^2.0.0",
-            "async-each": "^1.0.1",
-            "braces": "^2.3.2",
-            "fsevents": "^1.2.7",
-            "glob-parent": "^3.1.0",
-            "inherits": "^2.0.3",
-            "is-binary-path": "^1.0.0",
-            "is-glob": "^4.0.0",
-            "normalize-path": "^3.0.0",
-            "path-is-absolute": "^1.0.0",
-            "readdirp": "^2.2.1",
-            "upath": "^1.1.1"
-          }
-        },
-        "cliui": {
-          "version": "5.0.0",
-          "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
-          "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
-          "dev": true,
-          "requires": {
-            "string-width": "^3.1.0",
-            "strip-ansi": "^5.2.0",
-            "wrap-ansi": "^5.1.0"
-          },
-          "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==",
-              "dev": true
-            },
-            "strip-ansi": {
-              "version": "5.2.0",
-              "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-              "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
-              "dev": true,
-              "requires": {
-                "ansi-regex": "^4.1.0"
-              }
-            }
-          }
-        },
-        "emoji-regex": {
-          "version": "7.0.3",
-          "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
-          "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
-          "dev": true
-        },
-        "fill-range": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
-          "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
-          "dev": true,
-          "requires": {
-            "extend-shallow": "^2.0.1",
-            "is-number": "^3.0.0",
-            "repeat-string": "^1.6.1",
-            "to-regex-range": "^2.1.0"
-          },
-          "dependencies": {
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            }
-          }
-        },
-        "find-up": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
-          "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
-          "dev": true,
-          "requires": {
-            "locate-path": "^3.0.0"
-          }
-        },
-        "fsevents": {
-          "version": "1.2.13",
-          "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz",
-          "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==",
-          "dev": true,
-          "optional": true
-        },
-        "glob-parent": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
-          "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
-          "dev": true,
-          "requires": {
-            "is-glob": "^3.1.0",
-            "path-dirname": "^1.0.0"
-          },
-          "dependencies": {
-            "is-glob": {
-              "version": "3.1.0",
-              "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
-              "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
-              "dev": true,
-              "requires": {
-                "is-extglob": "^2.1.0"
-              }
-            }
-          }
-        },
-        "is-absolute-url": {
-          "version": "3.0.3",
-          "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz",
-          "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==",
-          "dev": true
-        },
-        "is-binary-path": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
-          "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
-          "dev": true,
-          "requires": {
-            "binary-extensions": "^1.0.0"
-          }
-        },
-        "is-fullwidth-code-point": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
-          "dev": true
-        },
-        "is-number": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
-          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
-          "dev": true,
-          "requires": {
-            "kind-of": "^3.0.2"
-          },
-          "dependencies": {
-            "kind-of": {
-              "version": "3.2.2",
-              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-              "dev": true,
-              "requires": {
-                "is-buffer": "^1.1.5"
-              }
-            }
-          }
-        },
-        "locate-path": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
-          "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
-          "dev": true,
-          "requires": {
-            "p-locate": "^3.0.0",
-            "path-exists": "^3.0.0"
-          }
-        },
-        "micromatch": {
-          "version": "3.1.10",
-          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
-          "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
-          "dev": true,
-          "requires": {
-            "arr-diff": "^4.0.0",
-            "array-unique": "^0.3.2",
-            "braces": "^2.3.1",
-            "define-property": "^2.0.2",
-            "extend-shallow": "^3.0.2",
-            "extglob": "^2.0.4",
-            "fragment-cache": "^0.2.1",
-            "kind-of": "^6.0.2",
-            "nanomatch": "^1.2.9",
-            "object.pick": "^1.3.0",
-            "regex-not": "^1.0.0",
-            "snapdragon": "^0.8.1",
-            "to-regex": "^3.0.2"
-          }
-        },
-        "p-locate": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
-          "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
-          "dev": true,
-          "requires": {
-            "p-limit": "^2.0.0"
-          }
-        },
-        "path-exists": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
-          "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=",
-          "dev": true
-        },
-        "readdirp": {
-          "version": "2.2.1",
-          "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
-          "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
-          "dev": true,
-          "requires": {
-            "graceful-fs": "^4.1.11",
-            "micromatch": "^3.1.10",
-            "readable-stream": "^2.0.2"
-          }
-        },
-        "schema-utils": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
-          "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==",
-          "dev": true,
-          "requires": {
-            "ajv": "^6.1.0",
-            "ajv-errors": "^1.0.0",
-            "ajv-keywords": "^3.1.0"
-          }
-        },
-        "semver": {
-          "version": "6.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
-          "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
-          "dev": true
-        },
-        "string-width": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
-          "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
-          "dev": true,
-          "requires": {
-            "emoji-regex": "^7.0.1",
-            "is-fullwidth-code-point": "^2.0.0",
-            "strip-ansi": "^5.1.0"
-          },
-          "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==",
-              "dev": true
-            },
-            "strip-ansi": {
-              "version": "5.2.0",
-              "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-              "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
-              "dev": true,
-              "requires": {
-                "ansi-regex": "^4.1.0"
-              }
-            }
-          }
-        },
-        "strip-ansi": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
-          "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^2.0.0"
-          }
-        },
-        "supports-color": {
-          "version": "6.1.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
-          "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^3.0.0"
-          }
-        },
-        "to-regex-range": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
-          "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
-          "dev": true,
-          "requires": {
-            "is-number": "^3.0.0",
-            "repeat-string": "^1.6.1"
-          }
-        },
-        "wrap-ansi": {
-          "version": "5.1.0",
-          "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
-          "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.0",
-            "string-width": "^3.0.0",
-            "strip-ansi": "^5.0.0"
-          },
-          "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==",
-              "dev": true
-            },
-            "strip-ansi": {
-              "version": "5.2.0",
-              "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
-              "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
-              "dev": true,
-              "requires": {
-                "ansi-regex": "^4.1.0"
-              }
-            }
-          }
-        },
-        "yargs": {
-          "version": "13.3.2",
-          "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
-          "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
-          "dev": true,
-          "requires": {
-            "cliui": "^5.0.0",
-            "find-up": "^3.0.0",
-            "get-caller-file": "^2.0.1",
-            "require-directory": "^2.1.1",
-            "require-main-filename": "^2.0.0",
-            "set-blocking": "^2.0.0",
-            "string-width": "^3.0.0",
-            "which-module": "^2.0.0",
-            "y18n": "^4.0.0",
-            "yargs-parser": "^13.1.2"
-          }
-        },
-        "yargs-parser": {
-          "version": "13.1.2",
-          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
-          "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
-          "dev": true,
-          "requires": {
-            "camelcase": "^5.0.0",
-            "decamelize": "^1.2.0"
+            "colorette": "^2.0.10",
+            "memfs": "^3.4.3",
+            "mime-types": "^2.1.31",
+            "range-parser": "^1.2.1",
+            "schema-utils": "^4.0.0"
           }
         }
       }
     },
-    "webpack-log": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz",
-      "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==",
-      "dev": true,
-      "requires": {
-        "ansi-colors": "^3.0.0",
-        "uuid": "^3.3.2"
-      }
-    },
     "webpack-merge": {
-      "version": "4.2.2",
-      "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz",
-      "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==",
+      "version": "5.8.0",
+      "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz",
+      "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==",
       "dev": true,
       "requires": {
-        "lodash": "^4.17.15"
+        "clone-deep": "^4.0.1",
+        "wildcard": "^2.0.0"
       }
     },
     "webpack-sources": {
-      "version": "1.4.3",
-      "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz",
-      "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==",
-      "dev": true,
-      "requires": {
-        "source-list-map": "^2.0.0",
-        "source-map": "~0.6.1"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
-      }
+      "version": "3.2.3",
+      "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz",
+      "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==",
+      "dev": true
     },
     "webpack-subresource-integrity": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.4.1.tgz",
-      "integrity": "sha512-XMLFInbGbB1HV7K4vHWANzc1CN0t/c4bBvnlvGxGwV45yE/S/feAXIm8dJsCkzqWtSKnmaEgTp/meyeThxG4Iw==",
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz",
+      "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==",
       "dev": true,
       "requires": {
-        "webpack-sources": "^1.3.0"
+        "typed-assert": "^1.0.8"
       }
     },
     "websocket-driver": {
-      "version": "0.6.5",
-      "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz",
-      "integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=",
+      "version": "0.7.4",
+      "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz",
+      "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==",
       "dev": true,
       "requires": {
+        "http-parser-js": ">=0.5.1",
+        "safe-buffer": ">=5.1.0",
         "websocket-extensions": ">=0.1.1"
       }
     },
@@ -12387,87 +20053,34 @@
       "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==",
       "dev": true
     },
-    "whatwg-mimetype": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz",
-      "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==",
-      "dev": true
-    },
-    "whatwg-url": {
-      "version": "8.4.0",
-      "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.4.0.tgz",
-      "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==",
-      "dev": true,
-      "requires": {
-        "lodash.sortby": "^4.7.0",
-        "tr46": "^2.0.2",
-        "webidl-conversions": "^6.1.0"
-      }
-    },
-    "when": {
-      "version": "3.6.4",
-      "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz",
-      "integrity": "sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=",
-      "dev": true
-    },
     "which": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
-      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
+      "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
       "dev": true,
       "requires": {
         "isexe": "^2.0.0"
       }
     },
-    "which-module": {
+    "wide-align": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
+      "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
+      "dev": true,
+      "requires": {
+        "string-width": "^1.0.2 || 2 || 3 || 4"
+      }
+    },
+    "wildcard": {
       "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
-      "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
-    },
-    "worker-farm": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz",
-      "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==",
-      "dev": true,
-      "requires": {
-        "errno": "~0.1.7"
-      }
-    },
-    "worker-plugin": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/worker-plugin/-/worker-plugin-5.0.0.tgz",
-      "integrity": "sha512-AXMUstURCxDD6yGam2r4E34aJg6kW85IiaeX72hi+I1cxyaMUtrvVY6sbfpGKAj5e7f68Acl62BjQF5aOOx2IQ==",
-      "dev": true,
-      "requires": {
-        "loader-utils": "^1.1.0"
-      },
-      "dependencies": {
-        "json5": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
-          "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
-          "dev": true,
-          "requires": {
-            "minimist": "^1.2.0"
-          }
-        },
-        "loader-utils": {
-          "version": "1.4.0",
-          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz",
-          "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==",
-          "dev": true,
-          "requires": {
-            "big.js": "^5.2.2",
-            "emojis-list": "^3.0.0",
-            "json5": "^1.0.1"
-          }
-        }
-      }
+      "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz",
+      "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==",
+      "dev": true
     },
     "wrap-ansi": {
-      "version": "6.2.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz",
-      "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==",
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+      "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
       "requires": {
         "ansi-styles": "^4.0.0",
         "string-width": "^4.1.0",
@@ -12503,62 +20116,54 @@
       "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
     },
     "ws": {
-      "version": "6.2.1",
-      "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
-      "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
+      "version": "8.13.0",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
+      "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
       "dev": true,
-      "requires": {
-        "async-limiter": "~1.0.0"
-      }
+      "requires": {}
     },
     "xhr2": {
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/xhr2/-/xhr2-0.2.0.tgz",
       "integrity": "sha512-BDtiD0i2iKPK/S8OAZfpk6tyzEDnKKSjxWHcMBVmh+LuqJ8A32qXTyOx+TVOg2dKvq6zGBq2sgKPkEeRs1qTRA=="
     },
-    "xtend": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
-      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
-      "dev": true
-    },
-    "y18n": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
-      "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w=="
-    },
     "yallist": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
       "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
       "dev": true
     },
+    "yaml": {
+      "version": "1.10.2",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+      "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+      "dev": true
+    },
     "yargs": {
-      "version": "15.3.0",
-      "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.0.tgz",
-      "integrity": "sha512-g/QCnmjgOl1YJjGsnUg2SatC7NUYEiLXJqxNOQU9qSpjzGtGXda9b+OKccr1kLTy8BN9yqEyqfq5lxlwdc13TA==",
+      "version": "16.2.0",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",
+      "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
       "requires": {
-        "cliui": "^6.0.0",
-        "decamelize": "^1.2.0",
-        "find-up": "^4.1.0",
-        "get-caller-file": "^2.0.1",
+        "cliui": "^7.0.2",
+        "escalade": "^3.1.1",
+        "get-caller-file": "^2.0.5",
         "require-directory": "^2.1.1",
-        "require-main-filename": "^2.0.0",
-        "set-blocking": "^2.0.0",
         "string-width": "^4.2.0",
-        "which-module": "^2.0.0",
-        "y18n": "^4.0.0",
-        "yargs-parser": "^18.1.0"
+        "y18n": "^5.0.5",
+        "yargs-parser": "^20.2.2"
+      },
+      "dependencies": {
+        "y18n": {
+          "version": "5.0.8",
+          "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+          "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
+        }
       }
     },
     "yargs-parser": {
-      "version": "18.1.3",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
-      "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
-      "requires": {
-        "camelcase": "^5.0.0",
-        "decamelize": "^1.2.0"
-      }
+      "version": "20.2.9",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz",
+      "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="
     },
     "yn": {
       "version": "3.1.1",
diff --git a/services/self-service/src/main/resources/webapp/package.json b/services/self-service/src/main/resources/webapp/package.json
index 8f3921c..6f47864 100644
--- a/services/self-service/src/main/resources/webapp/package.json
+++ b/services/self-service/src/main/resources/webapp/package.json
@@ -15,43 +15,47 @@
   },
   "private": true,
   "dependencies": {
-    "@angular/animations": "^10.2.1",
+    "@angular/animations": "^11.2.14",
     "@angular/cdk": "^10.2.6",
-    "@angular/common": "^10.2.1",
-    "@angular/compiler": "^10.2.1",
-    "@angular/core": "^10.2.1",
-    "@angular/forms": "^10.2.1",
-    "@angular/localize": "^10.2.1",
+    "@angular/common": "^11.2.14",
+    "@angular/compiler": "^11.2.14",
+    "@angular/core": "^11.2.14",
+    "@angular/forms": "^11.2.14",
+    "@angular/localize": "^11.2.14",
     "@angular/material": "^10.2.6",
     "@angular/material-moment-adapter": "^10.2.6",
-    "@angular/platform-browser": "^10.2.1",
-    "@angular/platform-browser-dynamic": "^10.2.1",
-    "@angular/platform-server": "^10.2.1",
-    "@angular/router": "^10.2.1",
+    "@angular/platform-browser": "^11.2.14",
+    "@angular/platform-browser-dynamic": "^11.2.14",
+    "@angular/platform-server": "^11.2.14",
+    "@angular/router": "^11.2.14",
     "core-js": "^3.6.5",
     "guacamole-common-js": "^1.2.0",
-    "moment": "^2.29.2",
-    "moment-timezone": "^0.5.31",
+    "lodash.isequal": "^4.5.0",
+    "moment": "^2.29.4",
+    "moment-timezone": "^0.5.35",
     "ng-daterangepicker": "^1.1.0",
     "ng2-ace-editor": "^0.3.9",
     "ngx-toastr": "^12.1.0",
     "rxjs": "^6.6.3",
     "rxjs-compat": "6.5.3",
-    "swagger-ui-dist": "^4.1.3",
-    "tslib": "^1.14.1",
+    "swagger-ui-dist": "^3.36.1",
+    "tslib": "^2.0.0",
     "web-animations-js": "^2.3.2",
     "zone.js": "^0.10.3"
   },
   "devDependencies": {
-    "@angular-devkit/build-angular": "^0.1002.0",
-    "@angular/cli": "^10.2.0",
-    "@angular/compiler-cli": "^10.2.1",
+    "@angular-devkit/build-angular": "^15.2.4",
+    "@angular/cli": "^11.2.19",
+    "@angular/compiler-cli": "^11.2.14",
     "@types/moment-timezone": "^0.5.30",
     "@types/node": "^12.11.1",
     "codelyzer": "^6.0.0",
     "ts-node": "~8.4.1",
-    "tslint": "^5.20.1",
-    "typescript": "^3.9.2",
-    "webpack-bundle-analyzer": "^3.9.0"
+    "tslint": "^6.1.3",
+    "typescript": "^4.1.6",
+    "webpack-bundle-analyzer": "^4.7.0"
+  },
+  "resolutions": {
+    "webpack": "^5.0.0"
   }
 }
diff --git a/services/self-service/src/main/resources/webapp/pom.xml b/services/self-service/src/main/resources/webapp/pom.xml
new file mode 100644
index 0000000..019fc53
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/pom.xml
@@ -0,0 +1,39 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>com.epam.datalab</groupId>
+    <artifactId>datalab</artifactId>
+    <version>1.0</version>
+    <relativePath>/../../../../../../pom.xml</relativePath>
+  </parent>
+  <artifactId>webapp</artifactId>
+  <name>Front End Module</name>
+
+  <properties>
+    <sonar.language>js</sonar.language>
+  </properties>
+
+  <build>
+    <sourceDirectory>src</sourceDirectory>
+  </build>
+</project>
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/administration-models/endpoint-model.ts b/services/self-service/src/main/resources/webapp/src/app/administration/administration-models/endpoint-model.ts
new file mode 100644
index 0000000..5ae5ce5
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/administration-models/endpoint-model.ts
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export interface Endpoint {
+    account: string;
+    cloudProvider: string;
+    endpoint_tag: string;
+    name: string;
+    status: string;
+    url: string;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/administration.module.ts b/services/self-service/src/main/resources/webapp/src/app/administration/administration.module.ts
index dfbbbf7..73bed3c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/administration.module.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/administration.module.ts
@@ -25,10 +25,11 @@
 import { RolesModule } from './roles';
 import {ConfigurationModule} from './configuration';
 import {OdahuModule} from './odahu';
+import { DirectivesModule } from '../core/directives';
 
 @NgModule({
-  imports: [CommonModule, ManagenementModule, ProjectModule, RolesModule, ConfigurationModule, OdahuModule],
+  imports: [ CommonModule, ManagenementModule, ProjectModule, RolesModule, ConfigurationModule, OdahuModule ],
   declarations: [],
-  exports: [ManagenementModule, ProjectModule, RolesModule, ConfigurationModule, OdahuModule]
+  exports: [ ManagenementModule, ProjectModule, RolesModule, ConfigurationModule, OdahuModule ]
 })
 export class AdministrationModule { }
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/configuration/configuration.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/configuration/configuration.component.html
index 89024aa..6070255 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/configuration/configuration.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/configuration/configuration.component.html
@@ -23,22 +23,26 @@
       <ng-template [ngIf]="endpoints">
         <label class="label">Selected endpoint </label>
         <div class="mat-reset">
-          <div class="control selector-wrapper">
+          <div class="control selector-wrapper" [ngClass]="{ 'disabled-select' : !isEndpointsMoreThanOne}">
             <mat-form-field [ngClass]="{ 'not-active' : services['provisioning'].isConfigChanged || services['self-service'].isConfigChanged || services['billing'].isConfigChanged }">
               <mat-label>Select endpoint</mat-label>
-                <mat-select 
-                  disableOptionCentering 
-                  [(value)]="activeEndpoint" 
-                  panelClass="top-select scrolling" 
-                  [disabled]="services['provisioning'].isConfigChanged || services['self-service'].isConfigChanged || services['billing'].isConfigChanged">
-                  <mat-option 
-                    *ngFor="let endpoint of endpoints" 
-                    [value]="endpoint.name" 
+                <mat-select
+                  disableOptionCentering
+                  [(value)]="activeEndpoint"
+                  panelClass="top-select scrolling"
+                  [disabled]="services['provisioning'].isConfigChanged
+                    || services['self-service'].isConfigChanged
+                    || services['billing'].isConfigChanged
+                    || !isEndpointsMoreThanOne"
+                  >
+                  <mat-option
+                    *ngFor="let endpoint of endpoints"
+                    [value]="endpoint.name"
                     (click)="setActiveEndpoint(endpoint.name)">
                     {{ endpoint.name === 'local' ? endpoint.name : endpoint.name + ' (external endpoint)'}}{{endpoint.status !== 'ACTIVE' ? ', inactive' : ''}}
                   </mat-option>
                 </mat-select>
-              <button class="caret">
+              <button class="caret" [disabled]="!isEndpointsMoreThanOne">
                 <i class="material-icons">keyboard_arrow_down</i>
               </button>
             </mat-form-field>
@@ -48,14 +52,14 @@
     </div>
     <div>
       <ng-template [ngIf]="activeTab.index !== 0">
-        <button 
+        <button
           mat-raised-button class="butt"
           (click)="action('save')"
           [disabled]="!services['provisioning'].isConfigChanged && !services['self-service'].isConfigChanged && !services['billing'].isConfigChanged"
         >
           Save
         </button>
-        <button 
+        <button
           mat-raised-button class="butt"
           (click)="action('discard')"
           [disabled]="!services['provisioning'].isConfigChanged && !services['self-service'].isConfigChanged && !services['billing'].isConfigChanged"
@@ -71,9 +75,9 @@
       >
         Restart
       </button>
-      <button 
-        mat-raised-button 
-        class="butt" 
+      <button
+        mat-raised-button
+        class="butt"
         (click)="refreshConfig()"
       >
         <i class="material-icons refresh-icon">autorenew</i>Refresh
@@ -82,16 +86,16 @@
   </div>
   <mat-divider></mat-divider>
   <div class="configuration-wrapper">
-    <mat-tab-group 
-      animationDuration="0.5ms" 
-      (selectedTabChange)="tabChanged($event)" 
+    <mat-tab-group
+      animationDuration="0.5ms"
+      (selectedTabChange)="tabChanged($event)"
       [selectedIndex]="activeTab.index"
     >
-      <mat-tab 
+      <mat-tab
         label="Main"
-        [disabled]="!(!services['provisioning'].isConfigChanged && 
-                      !services['self-service'].isConfigChanged && 
-                      !services['billing'].isConfigChanged) && 
+        [disabled]="!(!services['provisioning'].isConfigChanged &&
+                      !services['self-service'].isConfigChanged &&
+                      !services['billing'].isConfigChanged) &&
                       activeTab.index !== 0"
       >
         <h4>Main settings</h4>
@@ -101,20 +105,20 @@
             <div class="section-content">
               <ul class="list-menu selection-list">
                 <li *ngFor="let service of services | keys">
-                  <p 
-                    *ngIf="(activeEndpoint !== 'local' 
-                          && (service.key === 'provisioning' || service.key === 'billing') 
+                  <p
+                    *ngIf="(activeEndpoint !== 'local'
+                          && (service.key === 'provisioning' || service.key === 'billing')
                           || activeEndpoint === 'local')"
-                    class="list-item" 
-                    role="menuitem" 
+                    class="list-item"
+                    role="menuitem"
                   >
                     <span (click)="toggleSettings(service.key);$event.stopPropagation()" class="d-flex">
-                      <div class="checkbox-wrap">
+                      <span class="checkbox-wrap">
                         <datalab-checkbox
                           [checked]="services[service.key].selected"
                           (toggleSelection)="toggleSettings(service.key)"
                         ></datalab-checkbox>
-                      </div>
+                      </span>
                       {{service.value.label}}
                     </span>
                   </p>
@@ -125,28 +129,28 @@
         </div>
       </mat-tab>
 
-      <mat-tab 
+      <mat-tab
         label="Self-service"
         *ngIf="activeEndpoint === 'local'"
-        [disabled]="!(!services['provisioning'].isConfigChanged 
-                  && !services['self-service'].isConfigChanged 
-                  && !services['billing'].isConfigChanged) 
+        [disabled]="!(!services['provisioning'].isConfigChanged
+                  && !services['self-service'].isConfigChanged
+                  && !services['billing'].isConfigChanged)
                   && activeTab.index !== 1"
       >
         <h4>Edit self-service.yml</h4>
         <div class="editor-wrap">
-          <div 
-            #selfEditor 
-            ace-editor 
-            mode="yaml" 
-            [(text)]="services['self-service'].config" 
-            [autoUpdateContent]="true" 
+          <div
+            #selfEditor
+            ace-editor
+            mode="yaml"
+            [(text)]="services['self-service'].config"
+            [autoUpdateContent]="true"
             (textChange)="configUpdate('self-service')"
           ></div>
         </div>
       </mat-tab>
 
-      <mat-tab 
+      <mat-tab
         label="Provisioning"
         [disabled]="!(!services['provisioning'].isConfigChanged
                   && !services['self-service'].isConfigChanged
@@ -155,32 +159,32 @@
       >
         <h4>Edit provisioning.yml</h4>
         <div class="editor-wrap">
-          <div 
-            #provEditor 
-            ace-editor 
-            mode="yaml" 
-            [(text)]="services['provisioning'].config" 
-            [autoUpdateContent]="true" 
+          <div
+            #provEditor
+            ace-editor
+            mode="yaml"
+            [(text)]="services['provisioning'].config"
+            [autoUpdateContent]="true"
             (textChange)="configUpdate('provisioning')"
           ></div>
         </div>
       </mat-tab>
 
-      <mat-tab 
+      <mat-tab
         label="Billing"
-        [disabled]="!(!services['provisioning'].isConfigChanged 
-                  && !services['self-service'].isConfigChanged 
-                  && !services['billing'].isConfigChanged) 
+        [disabled]="!(!services['provisioning'].isConfigChanged
+                  && !services['self-service'].isConfigChanged
+                  && !services['billing'].isConfigChanged)
                   && activeTab.index !== 3"
       >
         <h4>Edit billing.yml</h4>
         <div class="editor-wrap">
-          <div 
-            #billingEditor 
-            ace-editor 
-            mode="yaml" 
-            [(text)]="services['billing'].config" 
-            [autoUpdateContent]="true" 
+          <div
+            #billingEditor
+            ace-editor
+            mode="yaml"
+            [(text)]="services['billing'].config"
+            [autoUpdateContent]="true"
             (textChange)="configUpdate('billing')"
           ></div>
         </div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/configuration/configuration.component.scss b/services/self-service/src/main/resources/webapp/src/app/administration/configuration/configuration.component.scss
index e230032..3c474e9 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/configuration/configuration.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/configuration/configuration.component.scss
@@ -110,3 +110,15 @@
   opacity: 0.38;
   pointer-events: none;
 }
+
+.disabled-select {
+  background-color: rgba(0, 0, 0, 0.12);
+  color: rgb(87, 114, 137);
+  opacity: 0.6;
+}
+
+.caret:disabled{
+  background-color: rgba(0, 0, 0, 0.12) !important;
+  color: rgb(87, 114, 137);
+  opacity: 0.6;
+}
\ No newline at end of file
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/configuration/configuration.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/configuration/configuration.component.ts
index 72157b7..58ff7f0 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/configuration/configuration.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/configuration/configuration.component.ts
@@ -305,15 +305,15 @@
 
           if (this.services['self-service'].selected) {
             this.messagesStatus.counter += 1;
-            this.restartSingleService(true, false, false, 'Self-service')
+            this.restartSingleService(true, false, false, 'Self-service');
           }
           if (this.services['provisioning'].selected) {
             this.messagesStatus.counter += 1;
-            this.restartSingleService(false, true, false, 'Provisioning service')
+            this.restartSingleService(false, true, false, 'Provisioning service');
           }
           if (this.services['billing'].selected) {
             this.messagesStatus.counter += 1;
-            this.restartSingleService(false, false, true, 'Billing service')
+            this.restartSingleService(false, false, true, 'Billing service');
           }
 
           let timer = setInterval(() => {
@@ -350,6 +350,10 @@
     this.getServicesConfig(this.activeEndpoint);
     this.activeTab.index = 0;
   }
+
+  get isEndpointsMoreThanOne() {
+    return this.endpoints.length > 1;
+  }
 }
 
 @Component({
@@ -365,13 +369,13 @@
 
     <div mat-dialog-content class="content">
       <ng-template [ngIf]="data.action === 'restart' && !data.environmentStatuses[data.activeEndpoint]?.length" ]>
-        <span class="strong">{{data.services.join(', ') | titlecase}}</span> 
+        <span class="strong">{{data.services.join(', ') | titlecase}}</span>
         <span class="strong" *ngIf="data.services.length > 1 || (data.services.length === 1 && data.services[0] !== 'self-service')"> service</span>
         <span class="strong" [hidden]="(data.services.length < 2) || data.services.length === 2 && data.services[0] === 'self-service'">s</span>: restarting will make DataLab unavailable for some time.
       </ng-template>
 
       <ng-template [ngIf]="data.action === 'restart' && data.environmentStatuses[data.activeEndpoint]?.length && filterProvisioning.length" ]>
-        <span class="strong" >{{filterProvisioning.join(', ') | titlecase}}</span> 
+        <span class="strong" >{{filterProvisioning.join(', ') | titlecase}}</span>
         <span class="strong" *ngIf="filterProvisioning.length > 1 || (filterProvisioning.length === 1 && filterProvisioning[0] !== 'self-service')"> service</span>
         <span [hidden]="(filterProvisioning.length < 2) || filterProvisioning.length === 2 && filterProvisioning[0] === 'self-service'">s</span>: restarting will make DataLab unavailable for some time.
       </ng-template>
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/endpoints/endpoints.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/endpoints/endpoints.component.ts
index 0dfffeb..1ba5e14 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/endpoints/endpoints.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/endpoints/endpoints.component.ts
@@ -110,22 +110,22 @@
   private initFormModel(): void {
     this.createEndpointForm = this._fb.group({
       name: ['', Validators.compose([
-        Validators.required, 
-        Validators.pattern(PATTERNS.namePattern), 
-        this.validateName.bind(this), 
+        Validators.required,
+        Validators.pattern(PATTERNS.namePattern),
+        this.validateName.bind(this),
         this.providerMaxLength.bind(this)
       ])],
       url: ['', Validators.compose([
-        Validators.required, 
-        Validators.pattern(PATTERNS.fullUrl), 
+        Validators.required,
+        Validators.pattern(PATTERNS.fullUrl),
         this.validateUrl.bind(this)
       ])],
       account: ['', Validators.compose([
-        Validators.required, 
+        Validators.required,
         Validators.pattern(PATTERNS.namePattern)
       ])],
       endpoint_tag: ['', Validators.compose([
-        Validators.required, 
+        Validators.required,
         Validators.pattern(PATTERNS.namePattern)
       ])]
     });
@@ -137,7 +137,7 @@
         () => {
           this.toastr.success('Endpoint successfully disconnected. All related resources are terminating!', 'Success!');
           this.getEndpointList();
-        }, 
+        },
         error => this.toastr.error(error.message || 'Endpoint creation failed!', 'Oops!')
       );
   }
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/index.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/index.ts
index ca34114..fa74fe0 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/index.ts
@@ -39,6 +39,7 @@
 import {EndpointsComponent, EndpointTestResultDialogComponent} from './endpoints/endpoints.component';
 import { ProjectModule } from '../project';
 import {CheckboxModule} from '../../shared/checkbox';
+import { ConvertActionTypePipeModule } from '../../core/pipes/convert-action-type-pipe';
 
 export * from './management.component';
 
@@ -54,6 +55,7 @@
         FormControlsModule,
         DirectivesModule,
         MaterialModule,
+        ConvertActionTypePipeModule,
         CheckboxModule
     ],
   declarations: [
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
index 9eefde9..8b9e8a0 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
@@ -18,14 +18,14 @@
   -->
 <div class="managment-wrapper scrolling" #pageWrapper (scroll)="scrollTable($event)" (resize)="onResize($event)">
   <div class="ani scrolling scroll-wrapper" #wrapper (scroll)="scrollTable($event)">
-    <div 
-      class="nav-buttons" 
+    <div
+      class="nav-buttons"
       [ngStyle]="{'width.px': userAgentIndex === -1 ? tableWrapperWidth - 3 : tableWrapperWidth - 7 }"
-      [ngClass]="{'border': tableEl['offsetHeight'] < tableWrapper.offsetHeight - 48}" 
+      [ngClass]="{'border': tableEl['offsetHeight'] < tableWrapper.offsetHeight - 48}"
       [hidden]="!(tableWrapper.offsetWidth - tableEl['offsetWidth'] < 0)"
     >
       <div class="button-container">
-        <button 
+        <button
           mat-mini-fab aria-label="Scroll left"
           (click)="sctollTo('left')"
           [ngClass]="{'not-allowed': wrapper.scrollLeft === 0 }"
@@ -34,7 +34,7 @@
         </button>
       </div>
       <div class="button-container" [ngClass]="{'not-allowed': checkMaxRight()}">
-        <button 
+        <button
           mat-mini-fab aria-label="Scroll right"
           (click)="sctollTo('right')"
           [ngClass]="{'not-allowed': !(isMaxRight | async)}"
@@ -61,10 +61,10 @@
           </button>
         </th>
         <td mat-cell *matCellDef="let element">
-          <ng-template 
-            [ngIf]="element.type !== 'odahu' 
-                  && element.type !== 'edge node' 
-                  && (element.status==='running' || element.status==='stopped') 
+          <ng-template
+            [ngIf]="element.type !== 'odahu'
+                  && element.type !== 'edge node'
+                  && (element.status==='running' || element.status==='stopped')
                   && !clustersInProgress(element.resources)"
           >
             <datalab-checkbox
@@ -79,10 +79,10 @@
       <ng-container matColumnDef="user">
         <th mat-header-cell *matHeaderCellDef class="user label-header">
           <span class="label">User</span>
-          <button 
-            mat-icon-button 
-            aria-label="More" 
-            class="ar" 
+          <button
+            mat-icon-button
+            aria-label="More"
+            class="ar"
             (click)="toggleFilterRow()"
           >
             <i class="material-icons">
@@ -105,17 +105,17 @@
       <ng-container matColumnDef="project">
         <th mat-header-cell *matHeaderCellDef class="project label-header">
           <span class="label">Project</span>
-          <button 
-            mat-icon-button 
-            aria-label="More" 
-            class="ar" 
+          <button
+            mat-icon-button
+            aria-label="More"
+            class="ar"
             (click)="toggleFilterRow()"
           >
             <i class="material-icons">
               <span *ngIf="filtering && filterForm.projects.length > 0 && !collapsedFilterRow">filter_list</span>
               <span [hidden]="filtering && filterForm.projects.length > 0 && !collapsedFilterRow">more_vert</span>
             </i>
-          </button> 
+          </button>
         </th>
         <td mat-cell *matCellDef="let element">{{ element.project }}</td>
       </ng-container>
@@ -123,10 +123,10 @@
       <ng-container matColumnDef="endpoint">
         <th mat-header-cell *matHeaderCellDef class="endpoint label-header">
           <span class="label">Endpoint</span>
-          <button 
-            mat-icon-button 
-            aria-label="More" 
-            class="ar" 
+          <button
+            mat-icon-button
+            aria-label="More"
+            class="ar"
             (click)="toggleFilterRow()"
           >
             <i class="material-icons">
@@ -141,10 +141,10 @@
       <ng-container matColumnDef="type">
         <th mat-header-cell *matHeaderCellDef class="type label-header">
           <span class="label">Name</span>
-          <button 
-            mat-icon-button 
-            aria-label="More" 
-            class="ar" 
+          <button
+            mat-icon-button
+            aria-label="More"
+            class="ar"
             (click)="toggleFilterRow()"
           >
             <i class="material-icons">
@@ -168,10 +168,10 @@
       <ng-container matColumnDef="shape">
         <th mat-header-cell *matHeaderCellDef class="shape label-header">
           <span class="label">Shape / Resource id</span>
-          <button 
-            mat-icon-button 
-            aria-label="More" 
-            class="ar" 
+          <button
+            mat-icon-button
+            aria-label="More"
+            class="ar"
             (click)="toggleFilterRow()"
           >
             <i class="material-icons">
@@ -190,10 +190,10 @@
       <ng-container matColumnDef="status">
         <th mat-header-cell *matHeaderCellDef class="status label-header">
           <span class="label">Status</span>
-          <button 
-            mat-icon-button 
-            aria-label="More" 
-            class="ar" 
+          <button
+            mat-icon-button
+            aria-label="More"
+            class="ar"
             (click)="toggleFilterRow()"
           >
             <i class="material-icons">
@@ -210,10 +210,10 @@
       <ng-container matColumnDef="resources">
         <th mat-header-cell *matHeaderCellDef class="resources label-header">
           <span class="label">Compute</span>
-          <button 
-            mat-icon-button 
-            aria-label="More" 
-            class="ar" 
+          <button
+            mat-icon-button
+            aria-label="More"
+            class="ar"
             (click)="toggleFilterRow()"
           >
             <i class="material-icons">
@@ -236,8 +236,8 @@
                 <div class="resource-actions">
                   <span class="not-allow">
                     <a class="start-stop-action" *ngIf="resource.image === 'docker.datalab-dataengine'">
-                      <i 
-                        class="material-icons" 
+                      <i
+                        class="material-icons"
                         (click)="toggleResourceAction(element, 'stop', resource)"
                         [ngClass]="{'not-allowed' : resource.status !== 'running' || selected?.length }"
                       >
@@ -246,8 +246,8 @@
                     </a>
                   </span>
                   <span class="not-allow">
-                    <a 
-                      class="remove_butt" 
+                    <a
+                      class="remove_butt"
                       (click)="toggleResourceAction(element, 'terminate', resource)"
                       [ngClass]="{ 'disabled' : element.status !== 'running' || (resource.status !== 'running' && resource.status !== 'stopped') || selected?.length }"
                     >
@@ -267,10 +267,10 @@
         </th>
         <td mat-cell *matCellDef="let element" class="settings actions-col">
           <span [ngClass]="{'not-allow' : selected?.length}">
-            <span 
-              #settings 
-              class="actions" 
-              (click)="actions.toggle($event, settings)" 
+            <span
+              #settings
+              class="actions"
+              (click)="actions.toggle($event, settings)"
               *ngIf="element.type !== 'edge node' && element.type !== 'odahu'"
               [ngClass]="{
                 'disabled' : (element.status !== 'running' && element.status !== 'stopped')
@@ -281,46 +281,56 @@
           <bubble-up #actions class="list-menu" position="bottom-left" alternative="top-left">
             <ul class="list-unstyled">
               <li
-                matTooltip="{{ element.type !== 'edge node' 
-                  ? 'Unable to stop notebook because at least one computational resource is in progress' 
+                matTooltip="{{ element.type !== 'edge node'
+                  ? 'Unable to stop notebook because at least one computational resource is in progress'
                   : 'Unable to stop edge node because at least one resource of this user is in progress' }}"
-                matTooltipPosition="above" 
+                matTooltipPosition="above"
                 [matTooltipDisabled]="!isResourcesInProgress(element)"
                 [hidden]="element.name === 'edge node' && element.status === 'stopped'"
               >
-                <div 
+                <div
                   (click)="toggleResourceAction(element, 'stop')"
-                  [ngClass]="{'not-allowed' : element.status === 'stopped' || element.status === 'stopping' || 
-                                              element.status === 'starting' || element.status === 'creating image' || 
+                  [ngClass]="{'not-allowed' : element.status === 'stopped' || element.status === 'stopping' ||
+                                              element.status === 'starting' || element.status === 'creating image' ||
                                               element.status === 'failed' || isResourcesInProgress(element)}"
                 >
                   <i class="material-icons">pause_circle_outline</i>
                   <span>Stop</span>
                 </div>
               </li>
-              <li 
+              <li
                 *ngIf="element.name !== 'edge node'"
                 matTooltip="Unable to terminate notebook because at least one compute is in progress"
-                matTooltipPosition="above" 
+                matTooltipPosition="above"
                 [matTooltipDisabled]="!isResourcesInProgress(element)"
               >
-                <div 
+                <div
                   (click)="toggleResourceAction(element, 'terminate')"
-                  [ngClass]="{'not-allowed' : element.status !== 'running' && 
-                                              element.status !== 'stopped' || 
+                  [ngClass]="{'not-allowed' : element.status !== 'running' &&
+                                              element.status !== 'stopped' ||
                                               isResourcesInProgress(element)}"
                 >
                   <i class="material-icons">phonelink_off</i>
                   <span>Terminate</span>
                 </div>
               </li>
-
-              <div *ngIf="element.name === 'edge node' && element.status === 'stopped'">
-                <li (click)="toggleResourceAction(element, 'run')">
+              <li
+                *ngIf="element.status === 'running'  && element.image !== 'docker.datalab-superset'
+                      && element.image !== 'docker.datalab-jupyterlab'"
+              >
+                <div
+                  (click)="toggleResourceAction(element, 'create image')"
+                >
+                  <i class="material-icons">view_module</i>
+                  <span>Create Image</span>
+                </div>
+              </li>
+              <li *ngIf="element.status === 'stopped'">
+                <div (click)="toggleResourceAction(element, 'start')">
                   <i class="material-icons">play_circle_outline</i>
                   <span>Start</span>
-                </li>
-              </div>
+                </div>
+              </li>
             </ul>
           </bubble-up>
         </td>
@@ -334,9 +344,9 @@
 
       <ng-container matColumnDef="user-filter" sticky>
         <th mat-header-cell *matHeaderCellDef class="filter-row-item">
-          <multi-select-dropdown 
-            (selectionChange)="onUpdate($event)" 
-            [type]="'users'" 
+          <multi-select-dropdown
+            (selectionChange)="onUpdate($event)"
+            [type]="'users'"
             [items]="filterConfiguration.users"
             [model]="filterForm.users"
           ></multi-select-dropdown>
@@ -345,11 +355,11 @@
 
       <ng-container matColumnDef="type-filter" sticky>
         <th mat-header-cell *matHeaderCellDef class="filter-row-item">
-          <input 
-            placeholder="Filter by name" 
-            type="text" 
+          <input
+            placeholder="Filter by name"
+            type="text"
             class="form-control filter-field"
-            [value]="filterForm.type" 
+            [value]="filterForm.type"
             (input)="onFilterNameUpdate($event.target['value'])"
           />
         </th>
@@ -357,20 +367,20 @@
 
       <ng-container matColumnDef="project-filter" sticky>
         <th mat-header-cell *matHeaderCellDef class="filter-row-item">
-          <multi-select-dropdown 
-            (selectionChange)="onUpdate($event)" 
+          <multi-select-dropdown
+            (selectionChange)="onUpdate($event)"
             [type]="'projects'"
-            [items]="filterConfiguration.projects" 
+            [items]="filterConfiguration.projects"
             [model]="filterForm.projects"
           ></multi-select-dropdown>
         </th>
       </ng-container>
       <ng-container matColumnDef="endpoint-filter" sticky>
         <th mat-header-cell *matHeaderCellDef class="filter-row-item">
-          <multi-select-dropdown 
-            (selectionChange)="onUpdate($event)" 
+          <multi-select-dropdown
+            (selectionChange)="onUpdate($event)"
             [type]="'endpoints'"
-            [items]="filterConfiguration.endpoints" 
+            [items]="filterConfiguration.endpoints"
             [model]="filterForm.endpoints"
           ></multi-select-dropdown>
         </th>
@@ -378,10 +388,10 @@
 
       <ng-container matColumnDef="shape-filter" sticky>
         <th mat-header-cell *matHeaderCellDef class="filter-row-item">
-          <multi-select-dropdown 
-            (selectionChange)="onUpdate($event)" 
+          <multi-select-dropdown
+            (selectionChange)="onUpdate($event)"
             [type]="'shapes'"
-            [items]="filterConfiguration.shapes" 
+            [items]="filterConfiguration.shapes"
             [model]="filterForm.shapes"
           ></multi-select-dropdown>
         </th>
@@ -389,10 +399,10 @@
 
       <ng-container matColumnDef="status-filter" sticky>
         <th mat-header-cell *matHeaderCellDef class="filter-row-item">
-          <multi-select-dropdown 
-            (selectionChange)="onUpdate($event)" 
+          <multi-select-dropdown
+            (selectionChange)="onUpdate($event)"
             [type]="'statuses'"
-            [items]="filterConfiguration.statuses" 
+            [items]="filterConfiguration.statuses"
             [model]="filterForm.statuses"
           ></multi-select-dropdown>
         </th>
@@ -400,10 +410,10 @@
 
       <ng-container matColumnDef="resource-filter" sticky>
         <th mat-header-cell *matHeaderCellDef class="filter-row-item">
-          <multi-select-dropdown 
-            (selectionChange)="onUpdate($event)" 
+          <multi-select-dropdown
+            (selectionChange)="onUpdate($event)"
             [type]="'resources'"
-            [items]="filterConfiguration.resources" 
+            [items]="filterConfiguration.resources"
             [model]="filterForm.resources"
           ></multi-select-dropdown>
         </th>
@@ -412,22 +422,22 @@
       <ng-container matColumnDef="actions-filter" sticky>
         <th mat-header-cell *matHeaderCellDef  class="actions-col filter-row-item">
           <div class="actions">
-            <button 
-              mat-icon-button 
-              class="btn reset" 
-              (click)="resetFilterConfigurations()" 
+            <button
+              mat-icon-button
+              class="btn reset"
+              (click)="resetFilterConfigurations()"
               [disabled]="!isFilterSelected"
             >
               <i class="material-icons">close</i>
             </button>
 
-            <button 
-              mat-icon-button 
-              class="btn apply" 
+            <button
+              mat-icon-button
+              class="btn apply"
               (click)="applyFilter(filterForm)"
               [disabled]="isFilterChanged"
             >
-              <i 
+              <i
                 class="material-icons"
                 [ngClass]="{'not-allowed': allFilteredEnvironmentData?.length == 0 && !filtering}"
               >
@@ -440,7 +450,7 @@
 
       <ng-container matColumnDef="placeholder">
         <td mat-footer-cell *matFooterCellDef colspan="8" class="no-border">
-          <div 
+          <div
             class="info"
             *ngIf="(!allFilteredEnvironmentData) && !filtering || (allFilteredEnvironmentData?.length == 0) && !filtering"
           >
@@ -451,36 +461,36 @@
       </ng-container>
 
       <ng-container matColumnDef="scrollButtons">
-        <td 
-          mat-footer-cell 
-          *matFooterCellDef 
-          colspan="9" 
+        <td
+          mat-footer-cell
+          *matFooterCellDef
+          colspan="9"
           class="buttons-wrap"
         ></td>
       </ng-container>
 
-      <tr 
-        mat-header-row 
-        *matHeaderRowDef="displayedColumns; sticky: true" 
+      <tr
+        mat-header-row
+        *matHeaderRowDef="displayedColumns; sticky: true"
         class="header-row"
       ></tr>
-      <tr 
-        [hidden]="!collapsedFilterRow" 
-        mat-header-row 
+      <tr
+        [hidden]="!collapsedFilterRow"
+        mat-header-row
         *matHeaderRowDef="displayedFilterColumns; sticky: true"
         class="filter-row"
       ></tr>
       <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
 
-      <tr 
-        [hidden]="allFilteredEnvironmentData?.length" 
-        mat-footer-row *matFooterRowDef="['placeholder']" 
+      <tr
+        [hidden]="allFilteredEnvironmentData?.length"
+        mat-footer-row *matFooterRowDef="['placeholder']"
         class="info"
       ></tr>
-      <tr 
-        [hidden]="!tableEl || !tableEl['offsetWidth'] || tableWrapper.offsetWidth - tableEl['offsetWidth'] > -16 || !allFilteredEnvironmentData?.length" 
-        mat-footer-row 
-        *matFooterRowDef="['scrollButtons']; sticky: true" 
+      <tr
+        [hidden]="!tableEl || !tableEl['offsetWidth'] || tableWrapper.offsetWidth - tableEl['offsetWidth'] > -16 || !allFilteredEnvironmentData?.length"
+        mat-footer-row
+        *matFooterRowDef="['scrollButtons']; sticky: true"
         class="info"
       ></tr>
     </table>
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
index d762610..d757eed 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
@@ -142,7 +142,7 @@
             this.applyFilter(this.cashedFilterForm || this.filterForm);
           }
           this.progressBarService.stopProgressBar();
-        }, 
+        },
         () => {
           this.progressBarService.stopProgressBar();
         }
@@ -186,8 +186,8 @@
 
     const containsStatus = (list, selectedItems) => {
       if (list) {
-        return list.filter((item: any) => { 
-          if (selectedItems.indexOf(item.status) !== -1) return item; 
+        return list.filter((item: any) => {
+          if (selectedItems.indexOf(item.status) !== -1) return item;
         });
       }
     };
@@ -196,30 +196,30 @@
     if (config) {
       filteredData = filteredData.filter(item => {
         const isUser = config.users.length > 0 ? (config.users.indexOf(item.user) !== -1) : true;
-        const isTypeName = item.name 
-          ? item.name.toLowerCase().indexOf(config.type.toLowerCase()) !== -1 
+        const isTypeName = item.name
+          ? item.name.toLowerCase().indexOf(config.type.toLowerCase()) !== -1
           : item.type.toLowerCase().indexOf(config.type.toLowerCase()) !== -1;
-        const isStatus = config.statuses.length > 0 
-          ? (config.statuses.indexOf(item.status) !== -1) 
+        const isStatus = config.statuses.length > 0
+          ? (config.statuses.indexOf(item.status) !== -1)
           : (config.type !== 'active');
-        const isShape = config.shapes.length > 0 
+        const isShape = config.shapes.length > 0
           ? (config.shapes.indexOf(item.shape) !== -1 ||
             config.shapes.indexOf(item.gpu_type) !== -1 ||
-            config.shapes.indexOf(`GPU count: ${item.gpu_count}`) !== -1) 
+            config.shapes.indexOf(`GPU count: ${item.gpu_count}`) !== -1)
           : true;
-        const isProject = config.projects.length > 0 
-          ? (config.projects.indexOf(item.project) !== -1) 
+        const isProject = config.projects.length > 0
+          ? (config.projects.indexOf(item.project) !== -1)
           : true;
-        const isEndpoint = config.endpoints.length > 0 
-          ? (config.endpoints.indexOf(item.endpoint) !== -1) 
+        const isEndpoint = config.endpoints.length > 0
+          ? (config.endpoints.indexOf(item.endpoint) !== -1)
           : true;
 
         const modifiedResources = containsStatus(item.resources, config.resources);
-        let isResources = config.resources.length > 0 
-          ? (modifiedResources && modifiedResources.length > 0) 
+        let isResources = config.resources.length > 0
+          ? (modifiedResources && modifiedResources.length > 0)
           : true;
-        if (config.resources.length > 0 && modifiedResources && modifiedResources.length > 0) { 
-          item.resources = modifiedResources; 
+        if (config.resources.length > 0 && modifiedResources && modifiedResources.length > 0) {
+          item.resources = modifiedResources;
         }
 
         if (config.resources && config.resources.length === 0 && config.type === 'active' ||
@@ -288,7 +288,13 @@
       }
     });
 
-    this.filterConfiguration = new ManagementConfigModel(users, '', projects, [...shapes, ...gpuTypes, ...gpuCounts], statuses, resources, endpoints);
+    this.filterConfiguration = new ManagementConfigModel(
+      users,
+      '',
+      projects,
+      [...shapes, ...gpuTypes, ...gpuCounts],
+      statuses, resources, endpoints
+    );
   }
 
   public openNotebookDetails(data) {
@@ -352,7 +358,10 @@
   selector: 'confirm-dialog',
   template: `
   <div class="dialog-header">
-    <h4 class="modal-title"><span class="capitalize">{{ data.action }}</span> resource</h4>
+    <h4 class="modal-title">
+      <span class="capitalize">{{ data.action }}</span>
+      <span *ngIf="data.action !== 'create image'"> resource</span>
+    </h4>
     <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
   </div>
   <div mat-dialog-content class="content">
@@ -387,7 +396,7 @@
                    'stopped': data.action==='stop', 'terminated': data.action === 'terminate'
                     }"
               >
-                {{data.action  === 'stop' ? 'Stopped' : 'Terminated'}}
+                {{data.action | convertactiontype}}
               </div>
             </div>
             <div class="clusters-list-item" *ngFor="let cluster of notebook?.resources">
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.html
index 4a4cf55..9de4cea 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.html
@@ -19,11 +19,11 @@
 
 <div class="base-retreat">
   <div class="sub-nav">
-    <div *ngIf="healthStatus?.admin" class="admin-group">
+    <div *ngIf="healthStatus?.admin || healthStatus?.projectAdmin" class="admin-group">
       <div class="action-select-wrapper admin-group" >
         <span class="action-button-wrapper">
           <button
-            type="button" 
+            type="button"
             class="butt actions-btn"
             mat-raised-button
             [disabled]="!selected.length"
@@ -34,31 +34,42 @@
           </button>
           </span>
         <div class="action-menu" *ngIf="isActionsOpen">
+          <button
+            type="button"
+            class="butt action-menu-item"
+            [ngClass]="{'disabled': !selectedStopped }"
+            mat-raised-button
+            [disabled]="!selectedStopped"
+            (click)="resourceAction('start');$event.stopPropagation()"
+          >
+            Run
+          </button>
           <span>
             <button
-              type="button" 
+              type="button"
               class="butt action-menu-item"
-              [ngClass]="{'disabled': selectedRunning.length === 0  || selectedStopped.length !== 0 }"
+              [ngClass]="{'disabled': !selectedRunning }"
               mat-raised-button
-              [disabled]="selectedRunning.length === 0"
-              (click)="resourseAction('stop');$event.stopPropagation()"
+              [disabled]="!selectedRunning"
+              (click)="resourceAction('stop');$event.stopPropagation()"
             >
               Stop
             </button>
           </span>
           <button
-            type="button" 
+            type="button"
             class="butt action-menu-item"
             mat-raised-button
-            (click)="resourseAction('terminate');$event.stopPropagation()"
+            (click)="resourceAction('terminate');$event.stopPropagation()"
           >
             Terminate
           </button>
         </div>
       </div>
-      <button 
-        mat-raised-button 
-        class="butt ssn" 
+      <button
+        *ngIf="healthStatus?.admin"
+        mat-raised-button
+        class="butt ssn"
         (click)="showEndpointsDialog()"
       >
         <i class="material-icons"></i>Endpoints
@@ -66,9 +77,10 @@
       <!-- <button mat-raised-button class="butt ssn" (click)="openSsnMonitorDialog()">
         <i class="material-icons"></i>SSN Monitor
       </button> -->
-      <button 
-        mat-raised-button 
-        class="butt env" 
+      <button
+        *ngIf="healthStatus?.admin"
+        mat-raised-button
+        class="butt env"
         (click)="openManageEnvironmentDialog()"
       >
         Manage DataLab quotas
@@ -77,21 +89,21 @@
         <i class="material-icons">backup</i>Backup
       </button> -->
     </div>
-    <button 
-      mat-raised-button 
-      class="butt" 
+    <button
+      mat-raised-button
+      class="butt"
       (click)="refreshGrid()"
     >
       <i class="material-icons refresh-icon">autorenew</i>Refresh
     </button>
   </div>
   <mat-divider></mat-divider>
-  <management-grid 
-    [currentUser]="user.toLowerCase()" 
+  <management-grid
+    [currentUser]="user.toLowerCase()"
     [isAdmin]="healthStatus?.admin"
-    [environmentsHealthStatuses]="healthStatus?.list_resources" 
+    [environmentsHealthStatuses]="healthStatus?.list_resources"
     (refreshGrid)="buildGrid()"
-    (actionToggle)="toggleResourceAction($event)" 
+    (actionToggle)="toggleResourceAction($event)"
     (emitSelectedList)="selectedList($event)"
   ></management-grid>
 </div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.scss b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.scss
index b0e0c3f..aae1b45 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.scss
@@ -37,3 +37,13 @@
     }
   }
 }
+
+.action-menu-item:disabled {
+  color: rgba(180, 179, 179, 0.87) !important;
+  background-color: white;
+  opacity: 1;
+}
+
+.action-menu {
+  z-index: 999;
+}
\ No newline at end of file
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
index 9ce01ad..d8f680a 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
@@ -29,7 +29,7 @@
   StorageService
 } from '../../core/services';
 
-import { EnvironmentModel, GeneralEnvironmentStatus } from './management.model';
+import {ActionsType, ActionTypeOptions, EnvironmentModel, GeneralEnvironmentStatus, ModalData, ModalDataType} from './management.model';
 import { HTTP_STATUS_CODES } from '../../core/util';
 import { BackupDilogComponent } from './backup-dilog/backup-dilog.component';
 import { SsnMonitorComponent } from './ssn-monitor/ssn-monitor.component';
@@ -42,6 +42,8 @@
 import { ConfirmationDialogComponent, ConfirmationDialogType } from '../../shared/modal-dialog/confirmation-dialog';
 import { ManagementGridComponent, ReconfirmationDialogComponent } from './management-grid/management-grid.component';
 import { FolderTreeComponent } from '../../resources/bucket-browser/folder-tree/folder-tree.component';
+import { StatusTypes } from '../../core/models';
+import {AmiCreateDialogComponent} from '../../resources/exploratory/ami-create-dialog';
 
 @Component({
   selector: 'environments-management',
@@ -55,8 +57,9 @@
   public dialogRef: any;
   public selected: any[] = [];
   public isActionsOpen: boolean = false;
-  public selectedRunning: any[];
-  public selectedStopped: any[];
+  public selectedRunning: boolean;
+  public selectedStopped: boolean;
+  public resourceStatus = StatusTypes;
 
   @ViewChild(ManagementGridComponent, { static: true }) managementGrid;
 
@@ -117,7 +120,7 @@
           total => {
             this.dialogRef = this.dialog.open(ManageEnvironmentComponent, { data: { projectsList, total }, panelClass: 'modal-xl-s' });
             this.dialogRef.afterClosed().subscribe(result => result && this.setBudgetLimits(result));
-          }, 
+          },
           () => this.toastr.error('Failed users list loading!', 'Oops!')
         );
     });
@@ -150,7 +153,7 @@
               result.status === HTTP_STATUS_CODES.OK && this.toastr.success('Budget limits updated!', 'Success!');
               this.buildGrid();
             }
-          }, 
+          },
           error => this.toastr.error(error.message, 'Oops!'));
     } else {
       this.healthStatusService.updateTotalBudgetData($event.total)
@@ -215,96 +218,16 @@
       this.isActionsOpen = false;
     }
 
-    this.selectedRunning = this.selected.filter(item => item.status === 'running');
-    this.selectedStopped = this.selected.filter(item => item.status === 'stopped');
+    this.selectedRunning = this.selected.every(item => item.status === this.resourceStatus.running);
+    this.selectedStopped = this.selected.every(item => item.status === this.resourceStatus.stopped);
   }
 
   public toogleActions() {
     this.isActionsOpen = !this.isActionsOpen;
   }
 
-  toggleResourceAction($event): void {
-    const { environment, action, resource } = $event;
-    if (resource) {
-      const resource_name = resource ? resource.computational_name : environment.name;
-      this.dialog.open(ReconfirmationDialogComponent, {
-        data: { 
-          action, 
-          resource_name, 
-          user: environment.user, 
-          type: 'cluster' 
-        },
-        width: '550px', 
-        panelClass: 'error-modalbox'
-      }).afterClosed().subscribe(result => {
-        result && this.manageEnvironmentAction({ action, environment, resource });
-      });
-    } else {
-      let notebooks = this.selected.length ? this.selected : [environment];
-      if (action === 'stop') {
-        notebooks = notebooks.filter(note => note.status !== 'stopped');
-        this.dialog.open(ReconfirmationDialogComponent, {
-          data: { 
-            notebooks: notebooks, 
-            type: 'notebook', 
-            action 
-          },
-          width: '550px', 
-          panelClass: 'error-modalbox'
-        }).afterClosed().subscribe((res) => {
-          if (res) {
-            notebooks.forEach((env) => {
-              this.manageEnvironmentsService.environmentManagement(env.user, 'stop', env.project, env.name)
-                .subscribe(response => {
-                  this.buildGrid();
-                },
-                  error => console.log(error)
-                );
-            });
-            this.clearSelection();
-          } else {
-            this.clearSelection();
-          }
-          this.isActionsOpen = false;
-        });
-      } else if (action === 'terminate') {
-        this.dialog.open(ReconfirmationDialogComponent, {
-          data: { 
-            notebooks: notebooks, 
-            type: 'notebook', 
-            action 
-          }, 
-          width: '550px', 
-          panelClass: 'error-modalbox'
-        }).afterClosed().subscribe((res) => {
-          if (res) {
-            notebooks.forEach((env) => {
-              this.manageEnvironmentsService.environmentManagement(env.user, 'terminate', env.project, env.name)
-                .subscribe(
-                  response => {
-                    this.buildGrid();
-                  },
-                  error => console.log(error)
-                );
-            });
-            this.clearSelection();
-          } else {
-            this.clearSelection();
-          }
-          this.isActionsOpen = false;
-        });
-        // } else if (action === 'run') {
-        //   this.healthStatusService.runEdgeNode().subscribe(() => {
-        //     this.buildGrid();
-        //     this.toastr.success('Edge node is starting!', 'Processing!');
-        //   }, () => this.toastr.error('Edge Node running failed!', 'Oops!'));
-        // } else if (action === 'recreate') {
-        //   this.healthStatusService.recreateEdgeNode().subscribe(() => {
-        //     this.buildGrid();
-        //     this.toastr.success('Edge Node recreation is processing!', 'Processing!');
-        //   }, () => this.toastr.error('Edge Node recreation failed!', 'Oops!'));
-      }
-    }
+  toggleResourceAction({ environment, action, resource = null}): void {
+    this.openDialog(environment, action, resource);
   }
 
   private clearSelection() {
@@ -316,7 +239,109 @@
     }
   }
 
-  public resourseAction(action) {
+  public resourceAction(action: ActionTypeOptions) {
     this.toggleResourceAction({ environment: this.selected, action: action });
   }
+
+  private openDialog(environment, action, resource) {
+    let config: ModalData = {
+      type: '',
+      action
+    };
+    const observer = {
+      next: (res) => {}
+    };
+
+    if (resource) {
+      config.resource_name = resource.computational_name;
+      config.user = environment.user;
+      config.type = ModalDataType.cluster;
+      observer.next = (res) => {
+        res && this.manageEnvironmentAction({ action, environment, resource });
+      };
+    } else {
+      const notebooks = this.selected.length ? this.selected : [environment];
+      config = this.getModalConfig(config, action, notebooks);
+      observer.next = (res) => {
+        if (res) {
+          notebooks.forEach((env) => {
+            if (action === 'create image') {
+              env['isAdmin'] = true;
+              env['userName'] = env.user;
+              this.dialog.open(AmiCreateDialogComponent, { data: env, panelClass: 'modal-sm' })
+                .afterClosed().subscribe(
+                () => this.buildGrid(),
+                error => console.log(error)
+              );
+            } else {
+              this.getNotebookAction(env, action);
+            }
+          });
+        }
+        this.clearSelection();
+      };
+      this.isActionsOpen = false;
+    }
+
+    // TODO if action run and recreate are restored, uncomment this piece of code
+
+    // if(action === 'run' || action === 'recreate') {
+    //   this.getHealthAction(action);
+    // } else {
+    //   this.dialog.open(ReconfirmationDialogComponent, {
+    //     data: config,
+    //     width: '550px',
+    //     panelClass: 'error-modalbox'
+    //   }).afterClosed().subscribe(observer);
+    // }
+
+    // TODO if action run and recreate are restored remove this piece of code
+      this.dialog.open(ReconfirmationDialogComponent, {
+        data: config,
+        width: '550px',
+        panelClass: 'error-modalbox'
+      }).afterClosed().subscribe(observer);
+  }
+
+  private getModalConfig(config: ModalData, action: ActionsType, notebooks: EnvironmentModel[]): ModalData {
+    config = {...config, type: ModalDataType.notebook};
+    if (action === ActionsType.stop) {
+      notebooks = notebooks.filter(note => note.status !== this.resourceStatus.stopped);
+      return {...config, notebooks};
+    }
+    if (action === ActionsType.start) {
+      notebooks = notebooks.filter(note => note.status === this.resourceStatus.stopped);
+      return {...config, notebooks};
+    }
+    return {...config, notebooks};
+  }
+
+  private getNotebookAction(env: EnvironmentModel, action: ActionTypeOptions): void {
+    this.manageEnvironmentsService.environmentManagement(env.user, action, env.project, env.name)
+      .subscribe(
+        () => this.buildGrid(),
+        error => console.log(error)
+      );
+  }
+
+  private getHealthAction(action: ActionsType) {
+    let nodeAction: ActionsType.run | ActionsType.recreate;
+    const observer = {
+      next: () => {
+        this.buildGrid();
+        this.toastr.success(`Edge Node ${nodeAction} is processing!`, 'Processing!');
+      },
+      error: () => this.toastr.error(`Edge Node ${nodeAction} failed!`, 'Oops!')
+    };
+    if (action === ActionsType.run) {
+      nodeAction = ActionsType.run;
+      this.healthStatusService.runEdgeNode().subscribe(observer);
+    }
+    if (action === ActionsType.recreate) {
+      nodeAction = ActionsType.recreate;
+      this.healthStatusService.recreateEdgeNode().subscribe(observer);
+    }
+  }
 }
+
+
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
index 2e67871..8c1103a 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
@@ -85,8 +85,14 @@
   status: string;
   projectAssigned: boolean;
   bucketBrowser: object;
+  connectedPlatforms: ConnectedPlatformsStatus;
 }
 
+export interface ConnectedPlatformsStatus {
+  add: boolean;
+  disconnect: boolean;
+  view: boolean;
+}
 
 export class ManagementConfigModel {
 
@@ -114,3 +120,28 @@
     this.endpoints = [];
   }
 }
+
+export interface ModalData {
+  action: ActionsType;
+  resource_name?: any;
+  user?: any;
+  type: string;
+  notebooks?: any;
+}
+
+export enum ModalDataType {
+  cluster = 'cluster',
+  notebook = 'notebook',
+}
+
+export enum ActionsType {
+  stop = 'stop',
+  terminate = 'terminate',
+  start = 'start',
+  run = 'run',
+  recreate = 'recreate',
+  createImage = 'create image'
+}
+
+export type ActionTypeOptions = 'stop' | 'terminate' | 'start' | 'createImage';
+
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/odahu/create-odahu-claster/create-odahu-cluster.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/odahu/create-odahu-claster/create-odahu-cluster.component.ts
index a4f8360..e33e2e9 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/odahu/create-odahu-claster/create-odahu-cluster.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/odahu/create-odahu-claster/create-odahu-cluster.component.ts
@@ -22,11 +22,11 @@
 import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
 import { ToastrService } from 'ngx-toastr';
 
-import { Project } from '../../project/project.component';
 import { ProjectService, OdahuDeploymentService } from '../../../core/services';
 
 import { DICTIONARY } from '../../../../dictionary/global.dictionary';
 import {CheckUtils, PATTERNS} from '../../../core/util';
+import { Project } from '../../project/project.model';
 
 
 @Component({
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/index.ts b/services/self-service/src/main/resources/webapp/src/app/administration/project/index.ts
index 8e57f0f..d1fd9d7 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/project/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/index.ts
@@ -23,15 +23,16 @@
 
 import { MaterialModule } from '../../shared/material.module';
 import { FormControlsModule } from '../../shared/form-controls';
-import { UnderscorelessPipeModule } from '../../core/pipes/underscoreless-pipe';
 
 import { ProjectFormComponent } from './project-form/project-form.component';
 import { ProjectListComponent } from './project-list/project-list.component';
 
 import { ProjectComponent, EditProjectComponent } from './project.component';
 import { ProjectDataService } from './project-data.service';
-import {BubbleModule} from "../../shared/bubble";
 import {InformMessageModule} from '../../shared/inform-message';
+import { DirectivesModule } from '../../core/directives';
+import { BubbleModule } from '../../shared';
+import { UnderscorelessPipeModule } from '../../core/pipes';
 
 @NgModule({
     imports: [
@@ -42,7 +43,8 @@
         FormControlsModule,
         UnderscorelessPipeModule,
         BubbleModule,
-        InformMessageModule
+        InformMessageModule,
+        DirectivesModule
     ],
   declarations: [ProjectComponent, EditProjectComponent, ProjectFormComponent, ProjectListComponent],
   entryComponents: [EditProjectComponent],
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-data.service.ts b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-data.service.ts
index 0cb20d2..ad9e5c3 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-data.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-data.service.ts
@@ -22,7 +22,7 @@
 import { mergeMap} from 'rxjs/operators';
 
 import { ProjectService, EndpointService } from '../../core/services';
-import { Project } from './project.component';
+import { Project } from './project.model';
 
 @Injectable()
 export class ProjectDataService {
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.html
index cd76e97..774f049 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.html
@@ -41,10 +41,10 @@
                 <span class="upload-icon"></span> Upload
                 <input (change)="onFileChange($event)" type="file" name="file" accept=".pub" />
               </span>
-              <button 
-                mat-raised-button 
-                type="button" 
-                class="butt butt-generate" 
+              <button
+                mat-raised-button
+                type="button"
+                class="butt butt-generate"
                 [ngClass]="{ 'not-allowed' : item }"
                 (click)="generateUserAccessKey()"
               >
@@ -57,19 +57,19 @@
             </div>
           </div>
           <div class="text-center m-bott-10">
-            <button 
-              mat-raised-button 
-              type="button" 
-              class="butt" 
-              [disabled]="item" 
+            <button
+              mat-raised-button
+              type="button"
+              class="butt"
+              [disabled]="item"
               (click)="reset()"
             >
               Clear
             </button>
-            <button 
-              mat-raised-button 
-              type="button" 
-              class="butt next" 
+            <button
+              mat-raised-button
+              type="button"
+              class="butt next"
               matStepperNext
             >
               Next
@@ -88,18 +88,18 @@
             <div class="control-group m-bott-10">
               <label class="label">Project name</label>
               <div class="control">
-                <input 
-                  type="text" 
-                  formControlName="name" 
+                <input
+                  type="text"
+                  formControlName="name"
                   placeholder="Enter project name"
-                  (blur)="generateProjectTag($event)" 
+                  (blur)="generateProjectTag($event)"
                   [ngClass]="{ 'not-allowed' : item }"
                 />
                 <span class="error" *ngIf="projectForm?.controls.name.hasError('duplication')">
                   This project name already exists.
                 </span>
-                <span 
-                  class="error" 
+                <span
+                  class="error"
                   *ngIf="!projectForm?.controls.name.valid
                       && !projectForm?.controls.name.hasError('duplication')
                       && !projectForm?.controls.name.hasError('limit')
@@ -114,10 +114,10 @@
             <div class="control-group m-bott-10">
               <label class="label">Project tag</label>
               <div class="control">
-                <input 
-                  readonly 
-                  type="text" 
-                  formControlName="tag" 
+                <input
+                  readonly
+                  type="text"
+                  formControlName="tag"
                   placeholder="< equal to project name >"
                   class="not-allowed"
                 />
@@ -127,10 +127,10 @@
               <label class="label">Endpoints</label>
               <div class="control selector-wrapper">
                 <mat-form-field>
-                  <mat-select 
+                  <mat-select
                     multiple
-                    disableOptionCentering 
-                    formControlName="endpoints" 
+                    disableOptionCentering
+                    formControlName="endpoints"
                     placeholder="Select endpoints"
                     panelClass="crete-project-dialog scrolling"
                   >
@@ -143,16 +143,16 @@
                         <i class="material-icons">clear</i>&nbsp;None
                       </a>
                     </mat-option>
-                    <mat-option 
-                      *ngFor="let endpoint of endpointsList" 
+                    <mat-option
+                      *ngFor="let endpoint of endpointsList"
                       [value]="endpoint.name"
                       [disabled]="isDisabled(endpoint.name) || endpoint.status !== 'ACTIVE'"
                     >
                       {{ endpoint.name === 'local' ? endpoint.name : endpoint.name + (endpoint.status !== 'ACTIVE' ? ' (inactive)' : '')}}
                     </mat-option>
-                    <mat-option 
-                      *ngIf="!endpointsList.length" 
-                      class="multiple-select empty ml-10" 
+                    <mat-option
+                      *ngIf="!endpointsList.length"
+                      class="multiple-select empty ml-10"
                       disabled
                     >
                       Endpoints list is empty
@@ -167,26 +167,26 @@
           </div>
 
           <div class="text-center m-bott-10">
-            <button 
-              mat-raised-button 
-              type="button" 
-              class="butt" 
-              [disabled]="item" 
+            <button
+              mat-raised-button
+              type="button"
+              class="butt"
+              [disabled]="item"
               (click)="reset()"
             >
               Clear
             </button>
-            <button 
-              mat-raised-button 
-              matStepperPrevious 
+            <button
+              mat-raised-button
+              matStepperPrevious
               class="butt"
             >
               <i class="material-icons arrow-icon">keyboard_arrow_left</i>Back
             </button>
-            <button 
-              mat-raised-button 
-              type="button" 
-              class="butt next" 
+            <button
+              mat-raised-button
+              type="button"
+              class="butt next"
               matStepperNext
             >
               Next<i class="material-icons arrow-icon">keyboard_arrow_right</i>
@@ -204,10 +204,10 @@
             <label class="label">Groups</label>
             <div class="control selector-wrapper">
               <mat-form-field>
-                <mat-select 
+                <mat-select
                   multiple
-                  disableOptionCentering 
-                  formControlName="groups" 
+                  disableOptionCentering
+                  formControlName="groups"
                   placeholder="Select user groups"
                   panelClass="crete-project-dialog scrolling"
                 >
@@ -238,26 +238,26 @@
 <!--                <span class="hold-label">Use shared image</span>-->
 <!--              </mat-slide-toggle>-->
 <!--            </div>-->
-            <button 
-              mat-raised-button 
-              type="button" 
-              class="butt" 
-              [disabled]="item" 
+            <button
+              mat-raised-button
+              type="button"
+              class="butt"
+              [disabled]="item"
               (click)="reset()"
             >
               Clear
             </button>
-            <button 
-              mat-raised-button 
-              matStepperPrevious 
+            <button
+              mat-raised-button
+              matStepperPrevious
               class="butt"
             >
               <i class="material-icons arrow-icon">keyboard_arrow_left</i>Back
             </button>
-            <button 
-              mat-raised-button 
-              type="button" 
-              class="butt butt-success" 
+            <button
+              mat-raised-button
+              type="button"
+              class="butt butt-success"
               [disabled]="!projectForm.valid"
               (click)="confirm(projectForm.value)"
             >
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.ts
index b5cd1b8..d6fe75c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.ts
@@ -27,9 +27,9 @@
 import { ProjectService, RolesGroupsService, EndpointService, UserAccessKeyService } from '../../../core/services';
 import { ProjectDataService } from '../project-data.service';
 import { CheckUtils, FileUtils, PATTERNS } from '../../../core/util';
-import { Project } from '../project.component';
 import { DICTIONARY } from '../../../../dictionary/global.dictionary';
 import {ConfirmationDialogComponent} from '../../../shared/modal-dialog/confirmation-dialog';
+import { Project } from '../project.model';
 
 export interface GenerateKey { privateKey: string; publicKey: string; }
 
@@ -88,7 +88,7 @@
         () => {
           this.toastr.success('Project updated successfully!', 'Success!');
           this.update.emit();
-        }, 
+        },
         error => this.toastr.error(error.message || 'Project update failed!', 'Oops!')
       );
   }
@@ -96,7 +96,7 @@
   public confirm(data) {
     if (this.item) {
       const deletedGroups = this.item.groups.filter((v) => !(this.projectForm.value.groups.includes(v)));
-      
+
       if (deletedGroups.length) {
         this.dialog.open(ConfirmationDialogComponent, {
           data: {notebook: deletedGroups, type: 5, manageAction: true}, panelClass: 'modal-md'
@@ -170,7 +170,7 @@
 
 
   public selectOptions(list, key, select?) {
-    const filter = key === 'endpoints' ? list.filter(el => el.status === 'ACTIVE').map(el => el.name) : list
+    const filter = key === 'endpoints' ? list.filter(el => el.status === 'ACTIVE').map(el => el.name) : list;
     this.projectForm.controls[key].setValue(select ? filter : []);
   }
 
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.html
index 51c8c59..912a660 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.html
@@ -28,7 +28,7 @@
       <td mat-cell *matCellDef="let element" class="groups">
         <div class="mat-chip-list-wrap scrolling">
           <mat-chip-list>
-            <mat-chip 
+            <mat-chip
               *ngFor="let group of element.groups"
               [matTooltip]="group"
               matTooltipPosition="above"
@@ -45,7 +45,7 @@
       <th mat-header-cell *matHeaderCellDef class="endpoints">
         <span class="label-endpoint"> Endpoint </span>
         <span class="label-endpoint-status"> Endpoint status </span>
-        <span class="label-status">Edge node status </span>
+        <span class="label-status">Edge node status</span>
       </th>
       <td mat-cell *matCellDef="let element" class="source endpoints">
         <div *ngIf="!element.endpoints?.length; else list">
@@ -63,9 +63,9 @@
                 {{ (endpoint.endpointStatus | titlecase) || 'N/A'}}
               </span>
             </div>
-            
+
             <span class="status resource-status" [ngClass]="endpoint?.status.toLowerCase() || ''">
-              {{ endpoint?.status.toLowerCase() }}
+              {{ endpoint?.status | titlecase }}
             </span>
           </div>
         </ng-template>
@@ -93,12 +93,25 @@
                 Stop edge node
               </a>
             </li>
-            <!-- <li class="project-seting-item " *ngIf="element.areTerminatedNode" (click)="openEdgeDialog('recreate', element)">
-              <i class="material-icons">refresh</i>
-              <a class="action">
-                Recreate edge node
-              </a>
-            </li> -->
+            <li
+                *ngIf="element.areTerminatedNode && isEndpointAvailable"
+                (click)="openEdgeDialog('recreate', element)"
+
+            >
+              <button class="project-setting-button"
+                      #recreateBtn
+                      datalabIsEndpointActive
+                      [endpointList]="element.endpoints"
+                      [matTooltip]="'Unable to recreate edge node if endpoint status is not active.'"
+                      matTooltipPosition="above"
+                      [matTooltipDisabled]="!isRecreateBtnDisabled(element.endpoints)"
+              >
+                <i class="material-icons">refresh</i>
+                <a class="action" >
+                  Recreate edge node
+                </a>
+              </button>
+            </li>
             <li class="project-seting-item " *ngIf="element.areStoppedNode || element.areRunningNode" (click)="openEdgeDialog('terminate', element)">
               <i class="material-icons">phonelink_off</i>
               <a class="action">
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.scss b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.scss
index 836b822..0abea7e 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.scss
@@ -138,7 +138,8 @@
   }
 }
 
-.project-seting-item {
+.project-seting-item,
+.project-setting-button{
   display: flex;
   align-items: center;
   padding: 10px;
@@ -157,6 +158,18 @@
   }
 }
 
+.project-setting-button {
+  width: 100%;
+  background-color: transparent;
+  border: none;
+}
+
+.disabled-button {
+  color: rgba(0,0,0,0.26);
+  background-color: rgba(0,0,0,0.12);
+  cursor: not-allowed;
+}
+
 .material-icons {
   font-size: 18px;
   padding-top: 1px;
@@ -171,11 +184,11 @@
 }
 
 .actions-list {
-  padding: 10px 15px;
+  padding: 10px 0px;
 }
 
 .mat-chip {
   max-width: 200px !important;
   white-space: nowrap;
   display: inline-block;
-}
\ No newline at end of file
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.ts
index 41a2127..9800bfe 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.ts
@@ -17,75 +17,65 @@
  * under the License.
  */
 
-import { Component, OnInit, Output, EventEmitter, OnDestroy, Inject, Input } from '@angular/core';
+import { Component, OnInit, Output, EventEmitter, OnDestroy, Inject, Input, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
 import { ToastrService } from 'ngx-toastr';
 import { MatTableDataSource } from '@angular/material/table';
 import { Subscription } from 'rxjs';
 import { MatDialogRef, MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog';
 
 import { ProjectDataService } from '../project-data.service';
-import { Project, Endpoint } from '../project.component';
 import {ProgressBarService} from '../../../core/services/progress-bar.service';
 import {EdgeActionDialogComponent} from '../../../shared/modal-dialog/edge-action-dialog';
+import { EndpointService } from '../../../core/services';
+import { Endpoint, ModifiedEndpoint, Project } from '../project.model';
+import { checkEndpointListUtil } from '../../../core/util';
+import { EndpointStatus } from '../project.config';
 
 @Component({
   selector: 'project-list',
   templateUrl: './project-list.component.html',
-  styleUrls: ['./project-list.component.scss', '../../../resources/computational/computational-resources-list/computational-resources-list.component.scss']
+  styleUrls: [
+    './project-list.component.scss',
+    '../../../resources/computational/computational-resources-list/computational-resources-list.component.scss'
+  ]
 })
 export class ProjectListComponent implements OnInit, OnDestroy {
+  @Input() isProjectAdmin: boolean;
+  @Output() editItem: EventEmitter<{}> = new EventEmitter();
+  @Output() toggleStatus: EventEmitter<{}> = new EventEmitter();
+
+  @ViewChild('recreateBtn') recreateBtn: ElementRef;
 
   displayedColumns: string[] = ['name', 'groups', 'endpoints', 'actions'];
   dataSource: Project[] | any = [];
   projectList: Project[];
+  isEndpointAvailable: boolean;
 
-  @Input() isProjectAdmin: boolean;
-  @Output() editItem: EventEmitter<{}> = new EventEmitter();
-  @Output() toggleStatus: EventEmitter<{}> = new EventEmitter();
   private subscriptions: Subscription = new Subscription();
 
   constructor (
     public toastr: ToastrService,
     private projectDataService: ProjectDataService,
     private progressBarService: ProgressBarService,
+    private endpointService: EndpointService,
     @Inject(MAT_DIALOG_DATA) public data: any,
     public dialogRef: MatDialogRef<ProjectListComponent>,
     public dialog: MatDialog,
   ) { }
 
-  ngOnInit() {
+  ngOnInit(): void {
     this.getProjectList();
+    this.getEndpointList();
   }
 
-  ngOnDestroy() {
+  ngOnDestroy(): void {
     this.subscriptions.unsubscribe();
   }
 
-  private getProjectList() {
-    this.progressBarService.startProgressBar();
-    this.subscriptions.add(this.projectDataService._projects
-      .subscribe(
-        (value: Project[]) => {
-          this.projectList = value;
-          if (this.projectList) {
-            this.projectList.forEach(project => {
-              project.areRunningNode = this.areResoursesInStatuses(project.endpoints, ['RUNNING']);
-              project.areStoppedNode = this.areResoursesInStatuses(project.endpoints, ['STOPPED']);
-              project.areTerminatedNode = this.areResoursesInStatuses(project.endpoints, ['TERMINATED', 'FAILED']);
-            });
-          }
-          if (value) this.dataSource = new MatTableDataSource(value);
-          this.progressBarService.stopProgressBar();
-        }, 
-        () => this.progressBarService.stopProgressBar()
-      )
-    );
-  }
-
   public showActiveInstances(): void {
     const filteredList = this.projectList.map(project => {
       project.endpoints = project.endpoints.filter((endpoint: Endpoint) => {
-        return endpoint.status !== 'TERMINATED' && endpoint.status !== 'TERMINATING' && endpoint.status !== 'FAILED'
+        return endpoint.status !== 'TERMINATED' && endpoint.status !== 'TERMINATING' && endpoint.status !== 'FAILED';
       });
       return project;
     });
@@ -97,37 +87,84 @@
     this.editItem.emit(item);
   }
 
-  public openEdgeDialog(action, project) {
-    const endpoints = project.endpoints.filter(endpoint => {
-      if (action === 'stop') {
-        return endpoint.status === 'RUNNING';
-      }
-      if (action === 'start') {
-        return endpoint.status === 'STOPPED';
-      }
-      if (action === 'terminate') {
-        return endpoint.status === 'RUNNING' || endpoint.status === 'STOPPED';
-      }
-      if (action === 'recreate') {
-        return endpoint.status === 'TERMINATED' || endpoint.status === 'FAILED';
-      }
-    });
+  public openEdgeDialog(action: string, project: Project) {
+    const endpoints = this.getFilteredEndpointList(action, project);
+
     if (action === 'terminate' && endpoints.length === 1) {
       this.toggleStatus.emit({ project, endpoint: endpoints, action, oneEdge: true });
     } else {
       this.dialog.open(EdgeActionDialogComponent, { data: { type: action, item: endpoints }, panelClass: 'modal-sm' })
         .afterClosed().subscribe(
-          endpoint => {
-            if (endpoint && endpoint.length) {
-              this.toggleStatus.emit({project, endpoint, action});
-            }
-          }, 
-          error => this.toastr.error(error.message || `Endpoint ${action} failed!`, 'Oops!')
-        );
+        endpoint => {
+          if (endpoint && endpoint.length) {
+            this.toggleStatus.emit({project, endpoint, action});
+          }
+        },
+        error => this.toastr.error(error.message || `Endpoint ${action} failed!`, 'Oops!')
+      );
     }
   }
 
   public areResoursesInStatuses(resources, statuses: Array<string>) {
     return resources.some(resource => statuses.some(status => resource.status === status));
   }
+
+  isRecreateBtnDisabled(endpointList: ModifiedEndpoint[]): boolean {
+    return checkEndpointListUtil(endpointList);
+  }
+
+  private getFilteredEndpointList(action: string, project) {
+    return project.endpoints.filter(endpoint => {
+      if (action === 'stop') {
+        return endpoint.status === EndpointStatus.running;
+      }
+      if (action === 'start') {
+        return endpoint.status === EndpointStatus.stopped;
+      }
+      if (action === 'terminate') {
+        return endpoint.status === EndpointStatus.running || endpoint.status === EndpointStatus.stopped;
+      }
+      if (action === 'recreate') {
+        const edgeNodeStatus = endpoint.status === EndpointStatus.terminated || endpoint.status === EndpointStatus.failed;
+        return edgeNodeStatus && endpoint.endpointStatus === 'ACTIVE';
+      }
+    });
+  }
+
+  private getProjectList() {
+    this.progressBarService.startProgressBar();
+    this.subscriptions.add(this.projectDataService._projects
+      .subscribe(
+        (value: Project[]) => {
+          this.modifyProjectList(value);
+          if (value) this.dataSource = new MatTableDataSource(value);
+          this.progressBarService.stopProgressBar();
+        },
+        () => this.progressBarService.stopProgressBar()
+      )
+    );
+  }
+
+  private modifyProjectList(value: Project[]): void {
+    this.projectList = value;
+    if (this.projectList) {
+      this.projectList.forEach(project => {
+        project.areRunningNode = this.areResoursesInStatuses(project.endpoints, [EndpointStatus.running]);
+        project.areStoppedNode = this.areResoursesInStatuses(project.endpoints, [EndpointStatus.stopped]);
+        project.areTerminatedNode = this.areResoursesInStatuses(project.endpoints, [EndpointStatus.terminated, EndpointStatus.failed]);
+      });
+    }
+  }
+
+  private getEndpointList() {
+    this.endpointService.getEndpointsData().subscribe(
+      (response: Endpoint[] | []) => {
+        this.isEndpointAvailable = this.checkIsEndpointAvailable(response);
+      }
+    );
+  }
+
+  private checkIsEndpointAvailable(data: Endpoint[] | []): boolean {
+    return  data.length ? true : false;
+  }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.ts
index 1409c7b..61e4865 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.ts
@@ -27,23 +27,8 @@
 import { NotificationDialogComponent } from '../../shared/modal-dialog/notification-dialog';
 import { ProjectListComponent } from './project-list/project-list.component';
 import { EnvironmentsDataService } from '../management/management-data.service';
+import { Project } from './project.model';
 
-export interface Endpoint {
-  name: string;
-  status: string;
-  edgeInfo: any;
-}
-
-export interface Project {
-  name: string;
-  endpoints: any;
-  tag: string;
-  groups: string[];
-  shared_image_enabled?: boolean;
-  areStoppedNode?: boolean;
-  areTerminatedNode?: boolean;
-  areRunningNode?: boolean;
-}
 
 @Component({
   selector: 'datalab-project',
@@ -118,8 +103,8 @@
   }
 
   public toggleStatus($event) {
-    const data = { 
-      'project_name': $event.project.name, 
+    const data = {
+      'project_name': $event.project.name,
       endpoint: $event.endpoint.map(endpoint => endpoint.name),
       'edge_status': $event.endpoint.map(endpoint => endpoint.status)[0]
     };
@@ -129,11 +114,11 @@
   private toggleStatusRequest(data, action, isOnlyOneEdge?) {
     if ( action === 'terminate') {
       const projectsResources = this.resources
-        .filter(resource => resource.project === data.project_name && resource.resource_type !== "edge node");
+        .filter(resource => resource.project === data.project_name && resource.resource_type !== 'edge node');
 
       const activeProjectsResources = projectsResources?.length ? projectsResources
         .filter(expl => expl.status !== 'terminated' && expl.status !== 'terminating' && expl.status !== 'failed') : [];
-        
+
       const termResources = data.endpoint.reduce((res, endp) => {
         res.push(...activeProjectsResources.filter(resource => resource.endpoint === endp));
         return res;
@@ -143,7 +128,7 @@
         this.edgeNodeAction(data, action);
       } else {
         this.dialog.open(NotificationDialogComponent, { data: {
-            type: 'terminateNode', 
+            type: 'terminateNode',
             item: {action: data, resources: termResources}
           }, panelClass: 'modal-sm' })
           .afterClosed().subscribe(result => {
@@ -161,7 +146,7 @@
         () => {
           this.refreshGrid();
           this.toastr.success(`Edge node ${this.toEndpointAction(action)} is in progress!`, 'Processing!');
-        }, 
+        },
         error => {
           this.toastr.error(error.message, 'Oops!');
         }
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project.config.ts b/services/self-service/src/main/resources/webapp/src/app/administration/project/project.config.ts
new file mode 100644
index 0000000..fa333d0
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project.config.ts
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export enum EndpointStatus {
+  terminated = 'TERMINATED',
+  terminating = 'TERMINATING',
+  failed = 'FAILED',
+  running = 'RUNNING',
+  stopped = 'STOPPED',
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project.model.ts b/services/self-service/src/main/resources/webapp/src/app/administration/project/project.model.ts
new file mode 100644
index 0000000..bfdc790
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project.model.ts
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export interface Endpoint {
+  name: string;
+  status: string;
+  edgeInfo: any;
+}
+
+export interface ModifiedEndpoint extends Endpoint {
+  endpointStatus?: 'ACTIVE' | 'INACTIVE';
+}
+
+export interface Project {
+  name: string;
+  endpoints: any;
+  tag: string;
+  groups: string[];
+  shared_image_enabled?: boolean;
+  areStoppedNode?: boolean;
+  areTerminatedNode?: boolean;
+  areRunningNode?: boolean;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/roles/index.ts b/services/self-service/src/main/resources/webapp/src/app/administration/roles/index.ts
index 28c16e2..a3e3984 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/roles/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/roles/index.ts
@@ -26,15 +26,17 @@
 import { RolesComponent, ConfirmDeleteUserAccountDialogComponent } from './roles.component';
 import { GroupNameValidationDirective } from './group-name-validarion.directive';
 import {InformMessageModule} from '../../shared/inform-message';
+import { DirectivesModule } from '../../core/directives';
 
 @NgModule({
     imports: [
-        CommonModule,
-        FormsModule,
-        ReactiveFormsModule,
-        MaterialModule,
-        FormControlsModule,
-        InformMessageModule
+      CommonModule,
+      FormsModule,
+      ReactiveFormsModule,
+      MaterialModule,
+      FormControlsModule,
+      InformMessageModule,
+      DirectivesModule
     ],
   declarations: [RolesComponent, ConfirmDeleteUserAccountDialogComponent, GroupNameValidationDirective],
   entryComponents: [ConfirmDeleteUserAccountDialogComponent],
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.html
index c5d04a7..45a2dbd 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.html
@@ -23,10 +23,10 @@
          matTooltipPosition="above"
          [matTooltipDisabled]="healthStatus?.admin"
     >
-      <button 
-        mat-raised-button 
-        class="butt add-group" 
-        (click)="stepperView = !stepperView" 
+      <button
+        mat-raised-button
+        class="butt add-group"
+        (click)="onAddGroupClick()"
         [disabled]="!healthStatus?.admin"
       >
         <i class="material-icons">people_outline</i>Add group
@@ -40,12 +40,13 @@
       <mat-step [completed]='false'>
         <ng-template matStepLabel>Groups</ng-template>
         <div class="inner-step mat-reset">
-          <input 
-            [validator]="groupValidation()" 
-            type="text" 
-            placeholder="Enter group name" 
+          <input
+            [validator]="groupValidation()"
+            isGroupNameUnique
+            type="text"
+            placeholder="Enter group name"
             [(ngModel)]="setupGroup"
-            #setupGroupName="ngModel" 
+            #setupGroupName="ngModel"
           />
           <div class="error" *ngIf="setupGroupName.errors?.patterns && setupGroupName.dirty">
             Group name can only contain letters, numbers, hyphens and '_'.
@@ -58,14 +59,14 @@
           </div>
         </div>
         <div class="text-center m-bott-10">
-          <button 
-            mat-raised-button 
-            (click)="resetDialog()" 
+          <button
+            mat-raised-button
+            (click)="resetDialog()"
             class="butt"
           >
             Cancel
           </button>
-          <button 
+          <button
             mat-raised-button
             matStepperNext class="butt"
             [disabled]="!setupGroup || setupGroupName.errors?.long || setupGroupName.errors?.duplicate || setupGroupName.errors?.patterns"
@@ -103,6 +104,7 @@
             <multi-level-select-dropdown
               (selectionChange)="onUpdate($event)"
               name="roles"
+              [isAddGroup]="true"
               [items]="rolesList"
               [model]="setupRoles"
               [isAdmin]="healthStatus?.admin"
@@ -114,16 +116,16 @@
             <i class="material-icons arrow-icon">keyboard_arrow_left</i>
             Back
           </button>
-          <button 
-            mat-raised-button 
-            (click)="resetDialog()" 
+          <button
+            mat-raised-button
+            (click)="resetDialog()"
             class="butt"
           >
             Cancel
           </button>
-          <button 
-            mat-raised-button 
-            (click)="manageAction('create', 'group')" 
+          <button
+            mat-raised-button
+            (click)="manageAction('create', 'group')"
             class="butt butt-success"
             [disabled]="!setupGroup || setupGroupName.errors?.patterns || setupGroupName.errors?.duplicate || !setupRoles.length"
           >
@@ -143,7 +145,7 @@
         <td mat-cell *matCellDef="let element" class="name">
           <div class="d-flex">
             <span
-              class="ellipsis" 
+              class="ellipsis"
               [matTooltip]="element.group"
               matTooltipPosition="above"
               [matTooltipClass]="'full-size-tooltip'">
@@ -172,23 +174,23 @@
         <th mat-header-cell *matHeaderCellDef class="users"> Users </th>
         <td mat-cell *matCellDef="let element" class="users-list ani">
           <mat-form-field class="chip-list">
-            <input 
-              #user 
-              matInput 
-              placeholder="Enter user login" 
+            <input
+              #user
+              matInput
+              placeholder="Enter user login"
               pattern="[@.-_0-9a-zA-Z]"
-              (keydown.enter)="addUser(user, element);" 
+              (keydown.enter)="addUser(user, element);"
               (keyup)="checkIfUserAdded(element, user.value)"
             />
-            <button 
-              mat-icon-button 
-              matSuffix 
-              (click)="addUser(user, element); user.value = ''" 
+            <button
+              mat-icon-button
+              matSuffix
+              (click)="addUser(user, element); user.value = ''"
               [disabled]="element.isUserAdded"
             >
-              <mat-icon 
-                matTooltip="User is already added to this group" 
-                matTooltipPosition="above" 
+              <mat-icon
+                matTooltip="User is already added to this group"
+                matTooltipPosition="above"
                 [matTooltipDisabled]="!element.isUserAdded"
               >
                 person_add
@@ -218,7 +220,7 @@
         <th mat-header-cell *matHeaderCellDef class="actions"></th>
         <td mat-cell *matCellDef="let element" class="actions">
           <div class="actions-wrapper">
-            <span 
+            <span
               class="action-disabled"
               matTooltip="Only admin can delete group."
               matTooltipPosition="above"
@@ -233,10 +235,10 @@
               </span>
             </span>
 
-            <span 
-              class="apply ani big-icon" 
+            <span
+              class="apply ani big-icon"
               matTooltip="Group cannot be updated without any selected role"
-              matTooltipPosition="above" 
+              matTooltipPosition="above"
               [matTooltipDisabled]="element.selected_roles.length > 0"
               [ngClass]="{ 'not-allowed' : !element.selected_roles.length || isGroupChanded(element)}"
               (click)="manageAction('update', 'group', element)"
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.ts
index dc119c7..642c522 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.ts
@@ -17,16 +17,16 @@
  * under the License.
  */
 
-import { Component, OnInit, Output, EventEmitter, Inject } from '@angular/core';
-import { ValidatorFn, FormControl } from '@angular/forms';
+import { Component, OnInit, Output, EventEmitter, Inject, ViewChild, ElementRef } from '@angular/core';
+import { ValidatorFn, FormControl, NgModel } from '@angular/forms';
 import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
 import { ToastrService } from 'ngx-toastr';
 
 import { RolesGroupsService, HealthStatusService, ApplicationSecurityService, AppRoutingService } from '../../core/services';
-import { CheckUtils, SortUtils } from '../../core/util';
+import { SortUtils } from '../../core/util';
 import { DICTIONARY } from '../../../dictionary/global.dictionary';
 import { ProgressBarService } from '../../core/services/progress-bar.service';
-import { ConfirmationDialogComponent, ConfirmationDialogType } from '../../shared/modal-dialog/confirmation-dialog';
+import {ConfirmationDialogComponent, ConfirmationDialogType} from '../../shared';
 
 @Component({
   selector: 'datalab-roles',
@@ -96,7 +96,7 @@
     );
   }
 
-  getGroupsData() {
+  getGroupsData(): void {
     this.rolesService.getGroupsData()
       .subscribe(
         list => this.updateGroupData(list),
@@ -169,6 +169,10 @@
               }
             });
           }
+          // TODO REMOVE THIS CODE AFTER IMAGE ROLE REFACTORING
+          setTimeout(() => {
+            this.checkAuthorize();
+          });
           deletedUsers = [];
         });
     }
@@ -240,11 +244,11 @@
   }
 
   public extractIds(sourceList, target) {
-    const map = new Map();
+    const mapObj = new Map();
     const mapped = sourceList.reduce((acc, item) => {
       target.includes(item.description) && acc.set(item._id, item.description);
       return acc;
-    }, map);
+    }, mapObj);
 
     return this.mapToObj(mapped);
   }
@@ -264,16 +268,10 @@
   }
 
   public groupValidation(): ValidatorFn {
-    const duplicateList: any = this.groupsData.map(item => item.group.toLowerCase());
     return <ValidatorFn>((control: FormControl) => {
       if (control.value && control.value.length > this.maxGroupLength) {
         return { long: true };
       }
-
-      if (control.value && duplicateList.includes(CheckUtils.delimitersFiltering(control.value.toLowerCase()))) {
-        return { duplicate: true };
-      }
-
       if (control.value && !this.groupnamePattern.test(control.value))
         return { patterns: true };
 
@@ -315,11 +313,30 @@
       return;
     }
     if (user.value && user.value.trim()) {
-      item.users instanceof Array ? item.users.push(user.value.trim()) : item.users = [user.value.trim()];
+      item.users = [...item.users, ...this.normalizeUserList(user.value)];
     }
     user.value = '';
   }
 
+  onAddGroupClick(): void {
+    this.stepperView = !this.stepperView;
+  }
+
+  private normalizeUserList(userNameList: string): string[] {
+    if (userNameList.includes(',')) {
+      return userNameList.split(',')
+                  .map(userName => userName.trim())
+                  .filter(userName => userName);
+    }
+    return [ userNameList ];
+  }
+
+  private checkAuthorize(): void {
+    this.applicationSecurityService.isLoggedIn().subscribe(() => {
+      this.getEnvironmentHealthStatus();
+    });
+  }
+
   private getEnvironmentHealthStatus() {
     this.healthStatusService.getEnvironmentHealthStatus()
       .subscribe((result: any) => {
@@ -341,9 +358,13 @@
   }
 
   public checkIfUserAdded(element: any, value: string) {
-    element.isUserAdded = element.users
-      .map(v => v.toLowerCase())
-      .includes(value.toLowerCase());
+    if (value.includes(',')) {
+      element.isUserAdded = element.users.some(userName => this.normalizeUserList(value).includes(userName));
+    } else {
+      element.isUserAdded = element.users
+        .map(v => v.toLowerCase())
+        .includes(value.toLowerCase());
+    }
   }
 }
 
@@ -367,18 +388,18 @@
     </p>
   </div>
   <div class="text-center">
-    <button 
-      type="button" 
-      class="butt" 
-      mat-raised-button 
+    <button
+      type="button"
+      class="butt"
+      mat-raised-button
       (click)="dialogRef.close()"
     >
       No
     </button>
-    <button 
-      type="button" 
-      class="butt butt-success" 
-      mat-raised-button 
+    <button
+      type="button"
+      class="butt butt-success"
+      mat-raised-button
       (click)="dialogRef.close(true)"
     >
       Yes
@@ -393,4 +414,4 @@
     public dialogRef: MatDialogRef<ConfirmDeleteUserAccountDialogComponent>,
     @Inject(MAT_DIALOG_DATA) public data: any
   ) { }
-}
\ No newline at end of file
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/app.routing.module.ts b/services/self-service/src/main/resources/webapp/src/app/app.routing.module.ts
index d166b7d..0d7a2b4 100644
--- a/services/self-service/src/main/resources/webapp/src/app/app.routing.module.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/app.routing.module.ts
@@ -18,7 +18,7 @@
  */
 
 import { ModuleWithProviders } from '@angular/core';
-import { Routes, RouterModule } from '@angular/router';
+import { RouterModule, Routes } from '@angular/router';
 
 import { LoginComponent } from './login/login.module';
 import { LayoutComponent } from './layout/layout.component';
@@ -31,18 +31,19 @@
 import { ProjectComponent } from './administration/project/project.component';
 import { RolesComponent } from './administration/roles/roles.component';
 import { SwaggerComponent } from './swagger';
-import { AuthorizationGuard, CheckParamsGuard, CloudProviderGuard, AdminGuard, AuditGuard } from './core/services';
-import {ConfigurationComponent} from './administration/configuration/configuration.component';
-import {ProjectAdminGuard} from './core/services/projectAdmin.guard';
-import {ReportingComponent} from './reports/reporting/reporting.component';
-import {OdahuComponent} from './administration/odahu/odahu.component';
-import {AuditComponent} from './reports/audit/audit.component';
+import { AdminGuard, AuditGuard, AuthorizationGuard, CheckParamsGuard, CloudProviderGuard, ImagePageResolveGuard } from './core/services';
+import { ConfigurationComponent } from './administration/configuration/configuration.component';
+import { ProjectAdminGuard } from './core/services/projectAdmin.guard';
+import { ReportingComponent } from './reports/reporting/reporting.component';
+import { AuditComponent } from './reports/audit/audit.component';
+import { ImagesComponent } from './resources/images/images.component';
+import { RoutingListConfig } from './core/configs/routing-list.config';
 
 const routes: Routes = [
   {
-    path: 'login',
+    path: RoutingListConfig.login,
     component: LoginComponent
-  }, 
+  },
   {
     path: '',
     canActivate: [CheckParamsGuard],
@@ -50,21 +51,33 @@
     children: [
       {
         path: '',
-        redirectTo: 'resources_list',
+        redirectTo: RoutingListConfig.instances,
         pathMatch: 'full'
-      }, 
+      },
       {
-        path: 'resources_list',
+        path: RoutingListConfig.instances,
         component: ResourcesComponent,
         canActivate: [AuthorizationGuard]
-      }, 
+      },
       {
-        path: 'billing_report',
+        path: RoutingListConfig.images,
+        component: ImagesComponent,
+        canActivate: [AuthorizationGuard],
+        resolve: {
+          projectList: ImagePageResolveGuard
+        },
+      },
+      {
+        path: RoutingListConfig.connectedPlatforms,
+        loadChildren: () => import('./resources/connected-platforms/connected-platforms.module').then(m => m.ConnectedPlatformsModule)
+      },
+      {
+        path: RoutingListConfig.billing,
         component: ReportingComponent,
         canActivate: [AuthorizationGuard, CloudProviderGuard]
-      }, 
+      },
       {
-        path: 'projects',
+        path: RoutingListConfig.projects,
         component: ProjectComponent,
         canActivate: [AuthorizationGuard, AdminGuard],
       },
@@ -73,55 +86,55 @@
       //   component: OdahuComponent,
       //   canActivate: [AuthorizationGuard, AdminGuard],
       // }, {
-        path: 'roles',
+        path: RoutingListConfig.users,
         component: RolesComponent,
         canActivate: [AuthorizationGuard, AdminGuard],
-      }, 
+      },
       {
-        path: 'environment_management',
+        path: RoutingListConfig.resources,
         component: ManagementComponent,
         canActivate: [AuthorizationGuard, AdminGuard]
-      }, 
+      },
       {
-        path: 'configuration',
+        path: RoutingListConfig.configuration,
         component: ConfigurationComponent,
         canActivate: [AuthorizationGuard, AdminGuard, ProjectAdminGuard]
       },
       {
-        path: 'swagger',
+        path: RoutingListConfig.swagger,
         component: SwaggerComponent,
         canActivate: [AuthorizationGuard]
-      }, 
+      },
       {
-        path: 'help/publickeyguide',
+        path: RoutingListConfig.publickeyguide,
         component: PublicKeyGuideComponent,
         canActivate: [AuthorizationGuard]
-      }, 
+      },
       {
-        path: 'help/accessnotebookguide',
+        path: RoutingListConfig.accessnotebookguide,
         component: AccessNotebookGuideComponent,
         canActivate: [AuthorizationGuard]
       },
       {
-        path: 'audit',
+        path: RoutingListConfig.audit,
         component: AuditComponent,
         canActivate: [AuthorizationGuard, AuditGuard],
       },
     ]
-  }, 
+  },
   {
     path: 'terminal/:id/:endpoint',
     component: WebterminalComponent
-  }, 
+  },
   {
     path: '403',
     component: AccessDeniedComponent,
     canActivate: [AuthorizationGuard]
-  }, 
+  },
   {
   path: '**',
   component: NotFoundComponent
   }
 ];
 
-export const AppRoutingModule: ModuleWithProviders<RouterModule> = RouterModule.forRoot(routes, { useHash: true });
+export const AppRoutingModule: ModuleWithProviders<RouterModule> = RouterModule.forRoot(routes, { useHash: true, relativeLinkResolution: 'corrected' });
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/configs/docker-image-name.ts b/services/self-service/src/main/resources/webapp/src/app/core/configs/docker-image-name.ts
new file mode 100644
index 0000000..4225b98
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/configs/docker-image-name.ts
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export enum DockerImageName {
+    jupyterJpu = 'docker.datalab-jupyter-gpu',
+    dataEngineService = 'docker.datalab-dataengine-service'
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/configs/image-template-name.ts b/services/self-service/src/main/resources/webapp/src/app/core/configs/image-template-name.ts
new file mode 100644
index 0000000..73b3cba
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/configs/image-template-name.ts
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export enum ImageTemplateName {
+  hdInsight = 'HDInsight cluster'
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/models/imageType.enum.ts b/services/self-service/src/main/resources/webapp/src/app/core/configs/imageType.enum.ts
similarity index 100%
rename from services/self-service/src/main/resources/webapp/src/app/core/models/imageType.enum.ts
rename to services/self-service/src/main/resources/webapp/src/app/core/configs/imageType.enum.ts
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/configs/providers.ts b/services/self-service/src/main/resources/webapp/src/app/core/configs/providers.ts
new file mode 100644
index 0000000..b63a229
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/configs/providers.ts
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export enum Providers {
+  aws = 'aws',
+  azure = 'azure',
+  gcp = 'gsp'
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/configs/routing-list.config.ts b/services/self-service/src/main/resources/webapp/src/app/core/configs/routing-list.config.ts
new file mode 100644
index 0000000..171f80c
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/configs/routing-list.config.ts
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export enum RoutingListConfig {
+  instances = 'instances',
+  images = 'images',
+  connectedPlatforms = 'connected-platforms',
+  login = 'login',
+  billing = 'billing',
+  projects = 'projects',
+  users = 'users',
+  resources = 'resources',
+  audit = 'audit',
+  configuration = 'configuration',
+  swagger = 'swagger',
+  publickeyguide = 'help/publickeyguide',
+  accessnotebookguide = 'help/accessnotebookguide',
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/configs/statusTypes.enum.ts b/services/self-service/src/main/resources/webapp/src/app/core/configs/statusTypes.enum.ts
new file mode 100644
index 0000000..9b6427b
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/configs/statusTypes.enum.ts
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export enum StatusTypes {
+    creating = 'creating',
+    running = 'running',
+    stopping = 'stopping',
+    stopped = 'stopped',
+    terminating = 'terminating',
+    terminated = 'terminated',
+    failed = 'failed'
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/core.module.ts b/services/self-service/src/main/resources/webapp/src/app/core/core.module.ts
index 20a4512..5ea5b4f 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/core.module.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/core.module.ts
@@ -48,9 +48,9 @@
 import { ErrorInterceptor } from './interceptors/error.interceptor';
 
 import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
-import {ConfigurationService} from './services/configutration.service';
-import {AuditGuard, OdahuDeploymentService} from './services';
-import {ProjectAdminGuard} from './services/projectAdmin.guard';
+import {  ConfigurationService } from './services/configutration.service';
+import {AuditGuard, OdahuDeploymentService, ImagesPageService} from './services';
+import {  ProjectAdminGuard } from './services/projectAdmin.guard';
 
 @NgModule({
   imports: [CommonModule],
@@ -90,6 +90,7 @@
         UserAccessKeyService,
         ConfigurationService,
         OdahuDeploymentService,
+        ImagesPageService,
 
         { provide: MatDialogRef, useValue: {} },
         { provide: MAT_DIALOG_DATA, useValue: [] },
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/directives/click-outside-with-material-select.directive.ts b/services/self-service/src/main/resources/webapp/src/app/core/directives/click-outside-with-material-select.directive.ts
new file mode 100644
index 0000000..78af96c
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/directives/click-outside-with-material-select.directive.ts
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Directive, ElementRef, Output, EventEmitter, HostListener, Input } from '@angular/core';
+
+@Directive({
+  selector: '[datalabClickedOutsideMatSelect]'
+})
+export class ClickedOutsideMatSelectDirective {
+  constructor(private el: ElementRef) { }
+  @Input() isFormOpened: boolean;
+  @Output() public clickedOutside = new EventEmitter();
+
+  @HostListener('document:click', ['$event.target'])
+  public onClick(target: any): void {
+    if (!this.isFormOpened) {
+      return;
+    }
+    const clickedInside = this.el.nativeElement.contains(target);
+    const isClickOnDropdown = [...target.classList].some(item => item.includes('mat-option'));
+    const isClickOnOverlay = [...target.classList].some(item => item.includes('cdk-overlay'));
+    const isClickOnForm = !clickedInside && !isClickOnDropdown && !isClickOnOverlay;
+
+    if (isClickOnForm) {
+      this.clickedOutside.emit(target);
+    }
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/directives/click-outside.directive.ts b/services/self-service/src/main/resources/webapp/src/app/core/directives/click-outside.directive.ts
index ad34ab2..1f818ff 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/directives/click-outside.directive.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/directives/click-outside.directive.ts
@@ -29,7 +29,7 @@
 
 export class ClickOutsideDirective implements OnInit, OnDestroy {
 
-  @Output('clickOutside') clickOutside: EventEmitter<Object>;
+  @Output() clickOutside: EventEmitter<Object>;
 
   private listening: boolean;
   private globalClick: any;
@@ -44,7 +44,7 @@
       delay(1),
       tap(() => {
         this.listening = true;
-      }),).subscribe(($event: MouseEvent) => {
+      })).subscribe(($event: MouseEvent) => {
         this.onGlobalClick($event);
       });
   }
@@ -76,4 +76,4 @@
     }
     return false;
   }
-}
\ No newline at end of file
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/directives/index.ts b/services/self-service/src/main/resources/webapp/src/app/core/directives/index.ts
index 83a0eae..57f767a 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/directives/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/directives/index.ts
@@ -22,14 +22,26 @@
 import { CommonModule } from '@angular/common';
 import { ClickOutsideDirective } from './click-outside.directive';
 import { ScrollDirective } from './scrollTo.directive';
-
-export * from './scrollTo.directive';
-export * from './click-outside.directive';
+import { IsEndpointsActiveDirective } from './is-endpoint-active.directive';
+import { ClickedOutsideMatSelectDirective } from './click-outside-with-material-select.directive';
+import { IsGroupNameUniqueDirective } from './is-group-name-unique.directive';
 
 @NgModule({
-  imports: [CommonModule],
-  declarations: [ClickOutsideDirective, ScrollDirective],
-  exports: [ClickOutsideDirective, ScrollDirective]
+  imports: [ CommonModule ],
+  declarations: [
+    ClickOutsideDirective,
+    ScrollDirective,
+    IsEndpointsActiveDirective,
+    ClickedOutsideMatSelectDirective,
+    IsGroupNameUniqueDirective
+  ],
+  exports: [
+    ClickOutsideDirective,
+    ScrollDirective,
+    IsEndpointsActiveDirective,
+    ClickedOutsideMatSelectDirective,
+    IsGroupNameUniqueDirective
+  ]
 })
 
 export class DirectivesModule { }
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/directives/is-endpoint-active.directive.ts b/services/self-service/src/main/resources/webapp/src/app/core/directives/is-endpoint-active.directive.ts
new file mode 100644
index 0000000..60c9bee
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/directives/is-endpoint-active.directive.ts
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Directive, ElementRef, HostListener, Input, OnInit, Renderer2 } from '@angular/core';
+
+import { ModifiedEndpoint } from '../../administration/project/project.model';
+import { checkEndpointListUtil } from '../util';
+
+
+@Directive({
+  selector: '[datalabIsEndpointActive]'
+})
+export class IsEndpointsActiveDirective implements OnInit {
+  @Input() endpointList: ModifiedEndpoint[];
+
+  private isButtonDisabled: boolean = false;
+
+  constructor (
+    private el: ElementRef,
+    private renderer: Renderer2
+  ) { }
+
+  ngOnInit(): void {
+    this.checkEndpointList(this.endpointList);
+    this.setStyle();
+  }
+
+  @HostListener('click', ['$event'])
+  onClick(event: Event): void {
+    if (this.isButtonDisabled) {
+      event.stopPropagation();
+    }
+  }
+
+  private setStyle() {
+    if (this.isButtonDisabled) {
+      this.renderer.addClass(this.el.nativeElement, 'disabled-button');
+    }
+  }
+
+  private checkEndpointList(endpointList: ModifiedEndpoint[]): void {
+    this.isButtonDisabled = checkEndpointListUtil(endpointList);
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/directives/is-group-name-unique.directive.ts b/services/self-service/src/main/resources/webapp/src/app/core/directives/is-group-name-unique.directive.ts
new file mode 100644
index 0000000..f41c88f
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/directives/is-group-name-unique.directive.ts
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Directive } from '@angular/core';
+import { AbstractControl, NG_ASYNC_VALIDATORS, ValidationErrors, Validator } from '@angular/forms';
+import { Observable, of } from 'rxjs';
+import { catchError, map, switchMap, take } from 'rxjs/operators';
+import { RolesGroupsService } from '../services';
+import { GroupModel } from '../models/role.model';
+import 'rxjs-compat/add/observable/timer';
+
+
+@Directive({
+  selector: '[isGroupNameUnique]',
+  providers: [{ provide: NG_ASYNC_VALIDATORS, useExisting: IsGroupNameUniqueDirective, multi: true }]
+})
+export class IsGroupNameUniqueDirective implements Validator {
+  constructor( private rolesService: RolesGroupsService ) {
+  }
+  validate(control: AbstractControl): Observable<ValidationErrors | null> {
+    return Observable.timer(300).pipe(
+      switchMap( () => {
+        return this.rolesService.getGroupsData().pipe(
+          map(res => this.isGroupExist(res, control.value)),
+          map(isGroupExist => (isGroupExist ? { duplicate: true } : null)),
+          catchError(() => of(null)),
+          take(1)
+        );
+      })
+    );
+  }
+
+  private isGroupExist(groupList: GroupModel[], comparedValue: string): boolean {
+    return groupList.some(({group}) => {
+      return  group.toLowerCase() === comparedValue.toLowerCase();
+    });
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/models/computationalResourceImage.model.ts b/services/self-service/src/main/resources/webapp/src/app/core/models/computationalResourceImage.model.ts
index b721b26..13727f7 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/models/computationalResourceImage.model.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/models/computationalResourceImage.model.ts
@@ -19,7 +19,7 @@
 
 import { ComputationalResourceApplicationTemplate } from './computationalResourceApplicationTemplate.model';
 import { ResourceShapeTypesModel } from './resourceShapeTypes.model';
-import { ImageType } from './imageType.enum';
+import { ImageType } from '../configs/imageType.enum';
 import { SortUtils } from '../util';
 
 export class ComputationalResourceImage {
@@ -44,9 +44,9 @@
       for (let index = 0; index < jsonModel.templates.length; index++) {
         this.application_templates.push(new ComputationalResourceApplicationTemplate(
           jsonModel.templates[index],
-          this.shapes, 
-          this.image, 
-          this.template_name, 
+          this.shapes,
+          this.image,
+          this.template_name,
           this.description)
         );
       }
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/models/exploratoryEnvironmentVersion.model.ts b/services/self-service/src/main/resources/webapp/src/app/core/models/exploratoryEnvironmentVersion.model.ts
index f715955..a144798 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/models/exploratoryEnvironmentVersion.model.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/models/exploratoryEnvironmentVersion.model.ts
@@ -18,7 +18,7 @@
  */
 
 import { ResourceShapeTypesModel } from './resourceShapeTypes.model';
-import { ImageType } from './imageType.enum';
+import { ImageType } from '../configs/imageType.enum';
 
 export class ExploratoryEnvironmentVersionModel {
   image: string;
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/models/index.ts b/services/self-service/src/main/resources/webapp/src/app/core/models/index.ts
index 9ab3bc6..d996c4c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/models/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/models/index.ts
@@ -23,5 +23,8 @@
 export * from './computationalResourceImage.model';
 export * from './computationalResourceApplicationTemplate.model';
 export * from './computationalResourceApplication.model';
-export * from './imageType.enum';
+export * from '../configs/imageType.enum';
+export * from '../configs/docker-image-name';
+export * from '../configs/statusTypes.enum';
+
 
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/models/role.model.ts b/services/self-service/src/main/resources/webapp/src/app/core/models/role.model.ts
new file mode 100644
index 0000000..b2249ae
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/models/role.model.ts
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+export interface GroupModel {
+  group: string;
+  roles: Role[];
+  users: string[];
+}
+
+export interface Role {
+  id: string;
+  description: string;
+  type: EntityType;
+  cloud: CloudType;
+  pages: string[];
+  computationals: string[];
+  exploratories: string[];
+  exploratory_shapes: string[];
+  groups: string[];
+  images: string[];
+}
+
+
+export type EntityType = 'NOTEBOOK' | 'COMPUTATIONAL' | 'IMAGE' | 'NOTEBOOK_SHAPE' | 'COMPUTATIONAL_SHAPE' | 'BILLING' | 'BUCKET_BROWSER' | 'ADMINISTRATION';
+
+export type CloudType = 'AWS' | 'AZURE' | 'GSP' | 'GENERAL';
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/pipes/convert-action-type-pipe/convert-action-type.pipe.ts b/services/self-service/src/main/resources/webapp/src/app/core/pipes/convert-action-type-pipe/convert-action-type.pipe.ts
new file mode 100644
index 0000000..1c47afc
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/pipes/convert-action-type-pipe/convert-action-type.pipe.ts
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Pipe, PipeTransform } from '@angular/core';
+import { ActionsType } from '../../../administration/management/management.model';
+
+const actionTypes = {
+    stopped: 'Stopped',
+    terminated: 'Terminated',
+    started: 'Starting',
+    creating: 'Creating Image',
+    unknown: 'Unknown type'
+};
+
+@Pipe({ name: 'convertactiontype' })
+
+export class ConvertActionTypePipe implements PipeTransform {
+  transform(value: string): string {
+    if (value === ActionsType.stop) {
+        return actionTypes.stopped;
+    }
+
+    if (value === ActionsType.start) {
+        return actionTypes.started;
+    }
+
+    if (value === ActionsType.terminate) {
+        return actionTypes.terminated;
+    }
+    if (value === ActionsType.createImage) {
+      return actionTypes.creating;
+    } else {
+        return actionTypes.unknown;
+    }
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/pipes/convert-action-type-pipe/index.ts b/services/self-service/src/main/resources/webapp/src/app/core/pipes/convert-action-type-pipe/index.ts
new file mode 100644
index 0000000..fcf8e0e
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/pipes/convert-action-type-pipe/index.ts
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { ConvertActionTypePipe } from './convert-action-type.pipe';
+
+@NgModule({
+  imports: [CommonModule],
+  declarations: [ConvertActionTypePipe],
+  exports: [ConvertActionTypePipe]
+})
+
+export class ConvertActionTypePipeModule { }
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/pipes/index.ts b/services/self-service/src/main/resources/webapp/src/app/core/pipes/index.ts
index 399ce1d..e81d99d 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/pipes/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/pipes/index.ts
@@ -23,3 +23,6 @@
 export * from './replace-breaks-pipe';
 export * from './highlight.pipe';
 export * from './convert-action-pipe';
+export * from './normalize-dropdown-multi-value';
+export * from './is-element-available-pipe';
+export * from './normalize-link';
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/pipes/is-element-available-pipe/index.ts b/services/self-service/src/main/resources/webapp/src/app/core/pipes/is-element-available-pipe/index.ts
new file mode 100644
index 0000000..ca0a397
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/pipes/is-element-available-pipe/index.ts
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { IsElementAvailablePipe } from './is-element-available.pipe';
+
+@NgModule({
+  imports: [CommonModule],
+  declarations: [IsElementAvailablePipe],
+  exports: [IsElementAvailablePipe]
+})
+
+export class IsElementAvailablePipeModule { }
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/pipes/is-element-available-pipe/is-element-available.pipe.ts b/services/self-service/src/main/resources/webapp/src/app/core/pipes/is-element-available-pipe/is-element-available.pipe.ts
new file mode 100644
index 0000000..31ed338
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/pipes/is-element-available-pipe/is-element-available.pipe.ts
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({ name: 'isElementAvailable' })
+
+export class IsElementAvailablePipe implements PipeTransform {
+  transform<T>(elementField: T, callback: (elementField: T, rest?: any[]) => boolean, ...rest: any[]): boolean {
+    return callback(elementField, rest);
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/pipes/library-name-normalize/index.ts b/services/self-service/src/main/resources/webapp/src/app/core/pipes/library-name-normalize/index.ts
new file mode 100644
index 0000000..48f7e5a
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/pipes/library-name-normalize/index.ts
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { LibraryNameNormalizePipe } from './library-name-normalize.pipe';
+
+@NgModule({
+  imports: [CommonModule],
+  declarations: [LibraryNameNormalizePipe],
+  exports: [LibraryNameNormalizePipe]
+})
+
+export class LibraryNameNormalizePipeModule { }
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/pipes/library-name-normalize/library-name-normalize.pipe.ts b/services/self-service/src/main/resources/webapp/src/app/core/pipes/library-name-normalize/library-name-normalize.pipe.ts
new file mode 100644
index 0000000..3782c3a
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/pipes/library-name-normalize/library-name-normalize.pipe.ts
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import {Pipe, PipeTransform} from '@angular/core';
+
+const  libNameList = {
+  os_pkg: 'Apt/Yum',
+  pip3: 'Python 3',
+  r_pkg: 'R packages',
+  java: 'Java',
+  others: 'Others'
+};
+
+@Pipe({name: 'libNameNormalize'})
+
+export class LibraryNameNormalizePipe implements PipeTransform {
+  transform(libGroupName: string): string {
+    if (!libGroupName) {
+      return '';
+    }
+    return libNameList[libGroupName];
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/pipes/normalize-dropdown-multi-value/index.ts b/services/self-service/src/main/resources/webapp/src/app/core/pipes/normalize-dropdown-multi-value/index.ts
new file mode 100644
index 0000000..bf380dd
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/pipes/normalize-dropdown-multi-value/index.ts
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { NormalizeDropdownMultiValuePipe } from './normalize-dropdown-multi-value.pipe';
+
+@NgModule({
+  imports: [CommonModule],
+  declarations: [NormalizeDropdownMultiValuePipe],
+  exports: [NormalizeDropdownMultiValuePipe]
+})
+
+export class NormalizeDropdownMultiValuePipeModule { }
+
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/pipes/normalize-dropdown-multi-value/normalize-dropdown-multi-value.pipe.ts b/services/self-service/src/main/resources/webapp/src/app/core/pipes/normalize-dropdown-multi-value/normalize-dropdown-multi-value.pipe.ts
new file mode 100644
index 0000000..a326cf3
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/pipes/normalize-dropdown-multi-value/normalize-dropdown-multi-value.pipe.ts
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({ name: 'normalizeDropdownMultiValue' })
+
+export class NormalizeDropdownMultiValuePipe implements PipeTransform {
+  transform(value: string[] | string, meaninglessValue: string = ''): string {
+    if (!value) {
+      return '';
+    }
+    if (typeof value === 'string') {
+      return value;
+    }
+    const filteredList = value.filter(item => item !== meaninglessValue);
+    const [firstValue] = filteredList;
+    if (filteredList.length === 1) {
+      return firstValue;
+    }
+
+    return filteredList.length === 1
+      ? firstValue
+      : `${firstValue} (+${filteredList.length - 1} others)`;
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/pipes/normalize-link/index.ts b/services/self-service/src/main/resources/webapp/src/app/core/pipes/normalize-link/index.ts
new file mode 100644
index 0000000..18c71d9
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/pipes/normalize-link/index.ts
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { NormalizeLinkPipe } from './normalize-link.pipe';
+
+@NgModule({
+  imports: [ CommonModule ],
+  declarations: [ NormalizeLinkPipe ],
+  exports: [ NormalizeLinkPipe ]
+})
+
+export class NormalizeLinkPipeModule { }
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/pipes/normalize-link/normalize-link.pipe.ts b/services/self-service/src/main/resources/webapp/src/app/core/pipes/normalize-link/normalize-link.pipe.ts
new file mode 100644
index 0000000..ecbd3ef
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/pipes/normalize-link/normalize-link.pipe.ts
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Pipe, PipeTransform } from '@angular/core';
+
+@Pipe({
+  name: 'normalizeLink'
+})
+export class NormalizeLinkPipe implements PipeTransform {
+  transform(value: string): string {
+    return value.includes('http') ? value : `//${value}`;
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/pipes/truncate-text-pipe/index.ts b/services/self-service/src/main/resources/webapp/src/app/core/pipes/truncate-text-pipe/index.ts
new file mode 100644
index 0000000..43e1c6e
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/pipes/truncate-text-pipe/index.ts
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { TruncateTextPipe } from './truncate-text.pipe';
+
+@NgModule({
+  imports: [CommonModule],
+  declarations: [TruncateTextPipe],
+  exports: [TruncateTextPipe]
+})
+
+export class TruncateTextPipeModule { }
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/pipes/truncate-text-pipe/truncate-text.pipe.ts b/services/self-service/src/main/resources/webapp/src/app/core/pipes/truncate-text-pipe/truncate-text.pipe.ts
new file mode 100644
index 0000000..28ddf9e
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/pipes/truncate-text-pipe/truncate-text.pipe.ts
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Pipe, PipeTransform } from '@angular/core';
+
+const MAX_SYMBOLS_COUNT = 255;
+
+@Pipe({
+    name: 'truncateTextPipe'
+})
+export class TruncateTextPipe implements PipeTransform {
+    transform(text: string, limit: number = MAX_SYMBOLS_COUNT): string {
+        if (!text) {
+            return '';
+        }
+        return text.length > limit
+            ? `${text.substring(0, limit)}...`
+            : text;
+    }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/appRouting.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/appRouting.service.ts
index 1a80759..3dd07cb 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/appRouting.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/appRouting.service.ts
@@ -34,7 +34,7 @@
   }
 
   redirectToHomePage(): void {
-    this.router.navigate(['/resources_list']);
+    this.router.navigate(['/instances']);
   }
 
   redirectToHealthStatusPage(): void {
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts
index 3bb326d..032565e 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts
@@ -24,6 +24,8 @@
 import { Dictionary } from '../collections';
 import { environment } from '../../../environments/environment';
 import { HTTPMethod } from '../util';
+import { ImageFilterFormValue, ImageParams } from '../../resources/images';
+import { AddPlatformFromValue } from '../../resources/connected-platforms/connected-platforms.models';
 
 // we can now access environment.apiUrl
 const API_URL = environment.apiUrl;
@@ -44,6 +46,7 @@
   private static readonly PROVISIONED_RESOURCES = 'provisioned_resources';
   private static readonly EXPLORATORY_ENVIRONMENT = 'exploratory_environment';
   private static readonly IMAGE = 'image';
+  private static readonly SHARE_ALL = 'share_all';
   private static readonly SCHEDULER = 'scheduler';
   private static readonly TEMPLATES = 'templates';
   private static readonly COMPUTATION_TEMPLATES = 'computation_templates';
@@ -81,6 +84,8 @@
   private static readonly AUDIT = 'audit';
   private static readonly CONFIG = 'config';
   private static readonly QUOTA = 'quota';
+  private static readonly IMAGE_PAGE = 'image_page';
+  private static readonly CONNECTED_PLATFORMS = 'connected_platforms';
 
   private requestRegistry: Dictionary<string>;
 
@@ -180,6 +185,45 @@
       null);
   }
 
+  buildGetUserImagePage(): Observable<any> {
+    return this.buildRequest(HTTPMethod.GET,
+      this.requestRegistry.Item(ApplicationServiceFacade.IMAGE_PAGE),
+      null);
+  }
+
+  buildFilterUserImagePage(params: ImageFilterFormValue): Observable<any> {
+    return this.buildRequest(HTTPMethod.POST,
+      this.requestRegistry.Item(ApplicationServiceFacade.IMAGE_PAGE),
+      params);
+  }
+
+  buildShareImageAllUsers(params: ImageParams): Observable<any> {
+    return this.buildRequest(HTTPMethod.POST,
+      this.requestRegistry.Item(ApplicationServiceFacade.SHARE_ALL),
+      params
+      );
+  }
+  buildGetConnectedPlatformsPage(): Observable<any> {
+    return this.buildRequest(HTTPMethod.GET,
+      `${this.requestRegistry.Item(ApplicationServiceFacade.CONNECTED_PLATFORMS)}/user`,
+      null
+      );
+  }
+
+  buildAddPlatform(platformParams: AddPlatformFromValue): Observable<any> {
+    return this.buildRequest(HTTPMethod.POST,
+      this.requestRegistry.Item(ApplicationServiceFacade.CONNECTED_PLATFORMS),
+      platformParams
+    );
+  }
+
+  buildDisconnectPlatform(platformName: string): Observable<any> {
+    return this.buildRequest(HTTPMethod.DELETE,
+      `${this.requestRegistry.Item(ApplicationServiceFacade.CONNECTED_PLATFORMS)}/${platformName}`,
+      null
+    );
+  }
+
   public buildGetTemplatesRequest(params): Observable<any> {
     return this.buildRequest(HTTPMethod.GET,
       this.requestRegistry.Item(ApplicationServiceFacade.TEMPLATES) + params,
@@ -432,6 +476,18 @@
       { observe: 'response', responseType: 'text' });
   }
 
+  public buildDeleteImage(data: string): Observable<any> {
+    return this.buildRequest(HTTPMethod.DELETE,
+      this.requestRegistry.Item(ApplicationServiceFacade.IMAGE),
+      data, { responseType: 'text', observe: 'response' });
+  }
+
+  public buildGetImageShareInfo(data: string): Observable<any> {
+    return this.buildRequest(HTTPMethod.GET,
+      this.requestRegistry.Item(ApplicationServiceFacade.IMAGE) + data,
+      null);
+  }
+
   public buildGetExploratorySchedule(data): Observable<any> {
     return this.buildRequest(HTTPMethod.GET,
       this.requestRegistry.Item(ApplicationServiceFacade.SCHEDULER),
@@ -469,13 +525,13 @@
       null);
   }
 
-  public buildEnvironmentManagement(param, data): Observable<any> {
+  public buildEnvironmentManagement(param, data, headers): Observable<any> {
     return this.buildRequest(HTTPMethod.POST,
       this.requestRegistry.Item(ApplicationServiceFacade.ENV) + param,
       data,
       {
         observe: 'response',
-        headers: { 'Content-Type': 'text/plain' }
+        headers
       });
   }
 
@@ -714,14 +770,16 @@
     // Exploratory Environment
     this.requestRegistry.Add(ApplicationServiceFacade.PROVISIONED_RESOURCES,
       '/api/infrastructure/info');
+    this.requestRegistry.Add(ApplicationServiceFacade.IMAGE_PAGE,
+      '/api/infrastructure_provision/exploratory_environment/image/user');
+    this.requestRegistry.Add(ApplicationServiceFacade.CONNECTED_PLATFORMS,
+      '/api/connected_platforms');
     this.requestRegistry.Add(ApplicationServiceFacade.EXPLORATORY_ENVIRONMENT,
       '/api/infrastructure_provision/exploratory_environment');
     this.requestRegistry.Add(ApplicationServiceFacade.TEMPLATES,
       '/api/infrastructure_templates');
     this.requestRegistry.Add(ApplicationServiceFacade.COMPUTATION_TEMPLATES,
     '/infrastructure_provision/computational_resources');
-    this.requestRegistry.Add(ApplicationServiceFacade.IMAGE,
-      '/api/infrastructure_provision/exploratory_environment/image');
     this.requestRegistry.Add(ApplicationServiceFacade.SCHEDULER,
       '/api/infrastructure_provision/exploratory_environment/scheduler');
 
@@ -733,9 +791,17 @@
     this.requestRegistry.Add(ApplicationServiceFacade.COMPUTATIONAL_RESOURCES_DATAENGINE,
       '/infrastructure_provision/computational_resources/dataengine'); // spark (azure|aws)
 
+
     this.requestRegistry.Add(ApplicationServiceFacade.COMPUTATIONAL_RESOURCES_TEMLATES,
       '/api/infrastructure_templates/computational_templates');
 
+
+    // Images
+    this.requestRegistry.Add(ApplicationServiceFacade.IMAGE,
+      '/api/infrastructure_provision/exploratory_environment/image');
+    this.requestRegistry.Add(ApplicationServiceFacade.SHARE_ALL,
+      '/api/infrastructure_provision/exploratory_environment/image/share');
+
     // Bucket browser
     this.requestRegistry.Add(ApplicationServiceFacade.BUCKET, '/api/bucket');
 
@@ -805,4 +871,4 @@
       return this.http.get(body ? (url + body) : url, opt);
     }
   }
-}
\ No newline at end of file
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/connected-platform-api.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/connected-platform-api.service.ts
new file mode 100644
index 0000000..bd71530
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/connected-platform-api.service.ts
@@ -0,0 +1,54 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Injectable } from '@angular/core';
+import { ApplicationServiceFacade } from './applicationServiceFacade.service';
+import { catchError } from 'rxjs/operators';
+import { ErrorUtils } from '../util';
+import { Observable } from 'rxjs';
+import { AddPlatformFromValue, ConnectedPlatformsInfo } from '../../resources/connected-platforms/connected-platforms.models';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class ConnectedPlatformApiService {
+
+  constructor(
+    private applicationServiceFacade: ApplicationServiceFacade
+  ) { }
+
+  getConnectedPlatformsPage(): Observable<ConnectedPlatformsInfo> {
+    return this.applicationServiceFacade.buildGetConnectedPlatformsPage()
+      .pipe(
+        catchError(ErrorUtils.handleServiceError)
+      );
+  }
+
+  addPlatform(platformParams: AddPlatformFromValue) {
+    return  this.applicationServiceFacade.buildAddPlatform(platformParams).pipe(
+      catchError(ErrorUtils.handleServiceError)
+    );
+  }
+
+  disconnectPlatform(platformName: string) {
+    return  this.applicationServiceFacade.buildDisconnectPlatform(platformName).pipe(
+      catchError(ErrorUtils.handleServiceError)
+    );
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/endpoint.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/endpoint.service.ts
index ae522c5..3a77464 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/endpoint.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/endpoint.service.ts
@@ -35,7 +35,6 @@
     return this.applicationServiceFacade
       .buildGetEndpointsData()
       .pipe(
-        map(response => response),
         catchError(ErrorUtils.handleServiceError));
   }
 
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/image-page-resolve.guard.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/image-page-resolve.guard.ts
new file mode 100644
index 0000000..3ad80e9
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/image-page-resolve.guard.ts
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Injectable } from '@angular/core';
+import { ActivatedRouteSnapshot, Resolve, Router, RouterStateSnapshot } from '@angular/router';
+import { Observable, of  } from 'rxjs';
+
+import { ProjectImagesInfo } from '../../resources/images';
+import { switchMap, take } from 'rxjs/operators';
+import { ImagesPageService } from './images-page.service';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class ImagePageResolveGuard implements Resolve<ProjectImagesInfo> {
+  constructor(
+    private router: Router,
+    private userImagesPageService: ImagesPageService
+  ) {}
+
+  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<ProjectImagesInfo> {
+    return this.userImagesPageService.getFilterImagePage().pipe(
+      switchMap((imagePageData: ProjectImagesInfo) => of(imagePageData)),
+      take(1)
+    );
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/images-page.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/images-page.service.ts
new file mode 100644
index 0000000..b87d2bf
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/images-page.service.ts
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import {  Injectable } from '@angular/core';
+import {  Observable } from 'rxjs';
+import { catchError } from 'rxjs/operators';
+import {  ErrorUtils } from '../util';
+
+import { ApplicationServiceFacade } from './applicationServiceFacade.service';
+import {
+  ImageActionType,
+  ImageFilterFormValue,
+  ProjectImagesInfo,
+  ImageParams,
+  URL_Chunk
+} from '../../resources/images';
+import { ShareDialogData, UserData } from '../../resources/exploratory/image-action-dialog/image-action.model';
+
+@Injectable()
+export class ImagesPageService {
+  constructor(
+    private applicationServiceFacade: ApplicationServiceFacade
+  ) { }
+
+
+  getFilterImagePage(): Observable<ProjectImagesInfo> {
+    return this.applicationServiceFacade.buildGetUserImagePage()
+      .pipe(
+        catchError(ErrorUtils.handleServiceError)
+      );
+  }
+
+  filterImagePage(params: ImageFilterFormValue): Observable<ProjectImagesInfo> {
+    return this.applicationServiceFacade.buildFilterUserImagePage(params)
+      .pipe(
+        catchError(ErrorUtils.handleServiceError)
+      );
+  }
+
+  shareImagesAllUser(shareParams: ImageParams): Observable<ProjectImagesInfo> {
+    return this.applicationServiceFacade.buildShareImageAllUsers(shareParams)
+      .pipe(
+        catchError(ErrorUtils.handleServiceError)
+      );
+  }
+
+   terminateImage(image: ImageParams, action: ImageActionType): Observable<ProjectImagesInfo> {
+    const url = `/${image.projectName}/${image.endpoint}/${image.imageName}/${action}`;
+
+    return this.applicationServiceFacade
+      .buildDeleteImage(JSON.stringify(url))
+      .pipe(
+        catchError(ErrorUtils.handleServiceError)
+      );
+  }
+
+  getImageShareInfo(imageInfo: ImageParams): Observable<ShareDialogData> {
+    const { imageName, projectName, endpoint} = imageInfo;
+    const url = `/${URL_Chunk.sharingInfo}/${imageName}/${projectName}/${endpoint}/`;
+    return this.applicationServiceFacade
+      .buildGetImageShareInfo(url)
+      .pipe(
+        catchError(ErrorUtils.handleServiceError)
+      );
+  }
+
+  getUserDataForShareDropdown(imageInfo: ImageParams, userData: string): Observable<UserData[]> {
+    const { imageName, projectName, endpoint} = imageInfo;
+    const url = `/${URL_Chunk.autocomplete}/${imageName}/${projectName}/${endpoint}?value=${userData}`;
+    return this.applicationServiceFacade
+      .buildGetImageShareInfo(url)
+      .pipe(
+        catchError(ErrorUtils.handleServiceError)
+      );
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/index.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/index.ts
index d847415..b4c34fa 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/index.ts
@@ -40,3 +40,5 @@
 export * from './project.service';
 export * from './odahu-deployment.service';
 export * from './endpoint.service';
+export * from './image-page-resolve.guard';
+export * from './images-page.service';
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/managementEnvironments.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/managementEnvironments.service.ts
index 2d21fd5..30e5937 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/managementEnvironments.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/managementEnvironments.service.ts
@@ -23,6 +23,7 @@
 
 import { ApplicationServiceFacade } from './applicationServiceFacade.service';
 import { ErrorUtils } from '../util';
+import { ActionTypeOptions } from '../../administration/management/management.model';
 
 @Injectable()
 export class ManageEnvironmentsService {
@@ -36,10 +37,11 @@
         catchError(ErrorUtils.handleServiceError));
   }
 
-  environmentManagement(data, action: string, project: string, resource: string, computational?: string): Observable<{}> {
+  environmentManagement(data, action: ActionTypeOptions, project: string, resource: string, computational?: string): Observable<{}> {
     const params = computational ? `/${action}/${project}/${resource}/${computational}` : `/${action}/${project}/${resource}`;
+    const headers = action === 'createImage' ? { 'Content-Type': 'application/json; charset=UTF-8' } : { 'Content-Type': 'text/plain' };
     return this.applicationServiceFacade
-      .buildEnvironmentManagement(params, data)
+      .buildEnvironmentManagement(params, data, headers)
       .pipe(
         map(response => response),
         catchError(ErrorUtils.handleServiceError));
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/rolesManagement.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/rolesManagement.service.ts
index 1776691..b82e9cf 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/rolesManagement.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/rolesManagement.service.ts
@@ -23,16 +23,16 @@
 
 import { ApplicationServiceFacade } from './applicationServiceFacade.service';
 import { ErrorUtils } from '../util';
+import { GroupModel } from '../models/role.model';
 
 @Injectable()
 export class RolesGroupsService {
   constructor(private applicationServiceFacade: ApplicationServiceFacade) { }
 
-  public getGroupsData(): Observable<{}> {
+  public getGroupsData(): Observable<GroupModel[]> {
     return this.applicationServiceFacade
       .buildGetGroupsData()
       .pipe(
-        map(response => response),
         catchError(ErrorUtils.handleServiceError));
   }
 
@@ -40,7 +40,6 @@
     return this.applicationServiceFacade
       .buildGetRolesData()
       .pipe(
-        map(response => response),
         catchError(ErrorUtils.handleServiceError));
   }
 
@@ -48,7 +47,6 @@
     return this.applicationServiceFacade
       .buildSetupNewGroup(data)
       .pipe(
-        map(response => response),
         catchError(ErrorUtils.handleServiceError));
   }
 
@@ -56,7 +54,6 @@
     return this.applicationServiceFacade
       .buildUpdateGroupData(data)
       .pipe(
-        map(response => response),
         catchError(ErrorUtils.handleServiceError));
   }
 
@@ -64,7 +61,6 @@
     return this.applicationServiceFacade
       .buildSetupRolesForGroup(data)
       .pipe(
-        map(response => response),
         catchError(ErrorUtils.handleServiceError));
   }
 
@@ -72,7 +68,6 @@
     return this.applicationServiceFacade
       .buildSetupUsersForGroup(data)
       .pipe(
-        map(response => response),
         catchError(ErrorUtils.handleServiceError));
   }
 
@@ -82,7 +77,6 @@
     return this.applicationServiceFacade
       .buildRemoveUsersForGroup(JSON.stringify(url))
       .pipe(
-        map(response => response),
         catchError(ErrorUtils.handleServiceError));
   }
 
@@ -92,7 +86,6 @@
     return this.applicationServiceFacade
       .buildRemoveGroupById(JSON.stringify(url))
       .pipe(
-        map(response => response),
         catchError(ErrorUtils.handleServiceError));
   }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/userResource.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/userResource.service.ts
index 3f2d5f8..406270b 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/userResource.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/userResource.service.ts
@@ -23,6 +23,9 @@
 
 import { ErrorUtils } from '../util/';
 import { ApplicationServiceFacade } from './applicationServiceFacade.service';
+import {
+  ComputationalResourceModel
+} from '../../resources/computational/computational-resource-create-dialog/computational.resource.model';
 
 @Injectable()
 export class UserResourceService {
@@ -37,7 +40,7 @@
         catchError(ErrorUtils.handleServiceError));
   }
 
-  public getComputationalTemplates(project, endpoint, provider): Observable<any> {
+  public getComputationalTemplates(project, endpoint, provider): Observable<ComputationalResourceModel> {
     const url = `/${project}/${endpoint}/templates`;
     return this.applicationServiceFacade
       .buildGetComputationTemplatesRequest(url, provider)
@@ -109,9 +112,9 @@
   }
 
   public suspendComputationalResource(
-    projectName: string, 
-    notebookName: string, 
-    computationalResourceName: string, 
+    projectName: string,
+    notebookName: string,
+    computationalResourceName: string,
     provider: string
   ): Observable<{}> {
     const body = JSON.stringify('/' + projectName + '/' + notebookName + '/' + computationalResourceName + '/terminate');
@@ -123,10 +126,10 @@
   }
 
   public toggleStopStartAction(
-    project: string, 
-    notebook: string, 
-    resource: string, 
-    action, 
+    project: string,
+    notebook: string,
+    resource: string,
+    action,
     provider: string
   ): Observable<{}> {
     const url = `/${project}/${notebook}/${resource}/${action}`;
@@ -181,7 +184,6 @@
   }
 
   public createAMI(data): Observable<any> {
-    const body = JSON.stringify(data);
     return this.applicationServiceFacade
       .buildCreateAMI(data)
       .pipe(
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/util/capitalize-util.ts b/services/self-service/src/main/resources/webapp/src/app/core/util/capitalize-util.ts
new file mode 100644
index 0000000..a22722e
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/util/capitalize-util.ts
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export const capitalizeUtil = (value: string): string => {
+  const firstLetter = value.substring(0, 1).toUpperCase();
+  return `${firstLetter}${value.substring(1).toLowerCase()}`;
+};
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/util/case-insensitive-sort-util.ts b/services/self-service/src/main/resources/webapp/src/app/core/util/case-insensitive-sort-util.ts
new file mode 100644
index 0000000..416d6cc
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/util/case-insensitive-sort-util.ts
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+export const caseInsensitiveSortUtil = (arr: string[]): string[] => arr.sort(((a, b) => a.toLowerCase() > b.toLowerCase() ? 1 : -1));
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/util/check-endpoint-list-util.ts b/services/self-service/src/main/resources/webapp/src/app/core/util/check-endpoint-list-util.ts
new file mode 100644
index 0000000..b8aa14a
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/util/check-endpoint-list-util.ts
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { ModifiedEndpoint } from '../../administration/project/project.model';
+
+export const checkEndpointListUtil = (endpointList: ModifiedEndpoint[]): boolean => {
+  const isAllInactiveEdgeNodeHaveInactiveEndpoint =  endpointList.filter(({status}) => status === 'TERMINATED' || status === 'FAILED')
+    .every(({endpointStatus}) => !endpointStatus || endpointStatus === 'INACTIVE');
+  return isAllInactiveEdgeNodeHaveInactiveEndpoint;
+};
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/util/checkUtils.ts b/services/self-service/src/main/resources/webapp/src/app/core/util/checkUtils.ts
index d1e6f53..ca3e5a2 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/util/checkUtils.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/util/checkUtils.ts
@@ -28,7 +28,7 @@
     STOPPING: 'DISCONNECTING',
     STOPPED: 'DISCONNECTED'
   };
-  
+
   public static isJSON(str) {
     try {
       JSON.parse(str);
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/util/helpUtils.ts b/services/self-service/src/main/resources/webapp/src/app/core/util/helpUtils.ts
index a0eae85..f3d48fe 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/util/helpUtils.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/util/helpUtils.ts
@@ -44,13 +44,14 @@
   }
 
   public static sortGpuTypes(gpuType: Array<string> = []): Array<string> {
-    
+
     const sortedTypes = [
-      'nvidia-tesla-t4', 
-      'nvidia-tesla-k80', 
-      'nvidia-tesla-p4', 
-      'nvidia-tesla-p100', 
-      'nvidia-tesla-v100'
+      'nvidia-tesla-t4',
+      'nvidia-tesla-k80',
+      'nvidia-tesla-p4',
+      'nvidia-tesla-p100',
+      'nvidia-tesla-v100',
+      'nvidia-tesla-a100'
     ];
 
     return sortedTypes.filter(el => gpuType.includes(el));;
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/util/index.ts b/services/self-service/src/main/resources/webapp/src/app/core/util/index.ts
index 8c04f80..78b23cd 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/util/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/util/index.ts
@@ -26,3 +26,6 @@
 export * from './checkUtils';
 export * from './patterns';
 export * from './http-methods';
+export * from './check-endpoint-list-util';
+export * from './case-insensitive-sort-util';
+export * from './capitalize-util';
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/util/sortUtils.ts b/services/self-service/src/main/resources/webapp/src/app/core/util/sortUtils.ts
index fa220da..9e06ec1 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/util/sortUtils.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/util/sortUtils.ts
@@ -56,7 +56,7 @@
   }
 
   public static flatDeep(arr, d = 1) {
-    return d > 0 
+    return d > 0
       ? arr.reduce((acc, val) => acc.concat(Array.isArray(val) ? this.flatDeep(val, d - 1) : val), [])
       : arr.slice();
   }
diff --git a/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.html b/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.html
index 1e3b8df..69aa1e2 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.html
@@ -23,10 +23,10 @@
     <ng-container matColumnDef="date">
       <th mat-header-cell *matHeaderCellDef class="th_date label-header">
         <div class="label"><span class="text">Date</span></div>
-        <button 
-          mat-icon-button 
-          aria-label="More" 
-          class="ar" 
+        <button
+          mat-icon-button
+          aria-label="More"
+          class="ar"
           (click)="toggleFilterRow()"
         >
           <i class="material-icons">
@@ -42,10 +42,10 @@
     <ng-container matColumnDef="user">
       <th mat-header-cell *matHeaderCellDef class="th_user label-header" [ngStyle]="{'z-index': 99}">
         <div class="label"><span class="audit-user"> User</span></div>
-        <button 
-          mat-icon-button 
-          aria-label="More" 
-          class="ar" 
+        <button
+          mat-icon-button
+          aria-label="More"
+          class="ar"
           (click)="toggleFilterRow()"
         >
           <i class="material-icons">
@@ -67,10 +67,10 @@
         <div class="label">
           <span class="text"> Action </span>
         </div>
-        <button 
-          mat-icon-button 
-          aria-label="More" 
-          class="ar" 
+        <button
+          mat-icon-button
+          aria-label="More"
+          class="ar"
           (click)="toggleFilterRow()"
         >
           <i class="material-icons">
@@ -100,10 +100,10 @@
     <ng-container matColumnDef="project">
       <th mat-header-cell *matHeaderCellDef class="th_project label-header">
         <div class="label"><span class="text">Project</span></div>
-        <button 
-          mat-icon-button 
-          aria-label="More" 
-          class="ar" 
+        <button
+          mat-icon-button
+          aria-label="More"
+          class="ar"
           (click)="toggleFilterRow()"
         >
           <i class="material-icons">
@@ -123,10 +123,10 @@
     <ng-container matColumnDef="resource-type">
       <th mat-header-cell *matHeaderCellDef class="th_resource-type label-header">
         <div class="label"><span class="text">Resource type</span></div>
-        <button 
-          mat-icon-button 
-          aria-label="More" 
-          class="ar" 
+        <button
+          mat-icon-button
+          aria-label="More"
+          class="ar"
           (click)="toggleFilterRow()"
         >
           <i class="material-icons">
@@ -146,15 +146,15 @@
         <div class="pagination-wrapper">
           <div class="selected-items-wrapper">
             <span>Items per page:</span>
-            <div class="select-wrapper">
+            <div class="select__wrapper">
               <div class="mat-reset">
                 <div class="control selector-wrapper">
                   <mat-form-field>
                     <mat-label></mat-label>
                     <mat-select [(value)]="showItemsPrPage">
-                      <mat-option 
-                        *ngFor="let item of itemsPrPage" 
-                        [value]="item" 
+                      <mat-option
+                        *ngFor="let item of itemsPrPage"
+                        [value]="item"
                         (click)="setItemsPrPage(item)"
                       >
                         {{ item }}
@@ -173,36 +173,36 @@
           </span>
           <span>
             <span [ngClass]="{'not-active':  !isNavigationDisabled || firstItem === 1}">
-              <span 
-                class="navigation-butts" 
-                (click)="loadItemsForPage('first')" 
+              <span
+                class="navigation-butts"
+                (click)="loadItemsForPage('first')"
                 [ngClass]="{'not-allowed': firstItem === 1 || !isNavigationDisabled}"
               >
                 <i class="material-icons">first_page</i>
               </span>
             </span>
             <span [ngClass]="{'not-active': firstItem === 1 || !isNavigationDisabled}">
-              <span 
-                class="navigation-butts" 
-                (click)="loadItemsForPage('previous')" 
+              <span
+                class="navigation-butts"
+                (click)="loadItemsForPage('previous')"
                 [ngClass]="{'not-allowed': firstItem === 1 || !isNavigationDisabled}"
               >
                 <i class="material-icons">keyboard_arrow_left</i>
               </span>
             </span>
             <span [ngClass]="{'not-active': lastItem >= allItems || !isNavigationDisabled}">
-              <span 
-                class="navigation-butts" 
-                (click)="loadItemsForPage('next')" 
+              <span
+                class="navigation-butts"
+                (click)="loadItemsForPage('next')"
                 [ngClass]="{'not-allowed': lastItem >= allItems || !isNavigationDisabled}"
               >
                 <i class="material-icons">keyboard_arrow_right</i>
               </span>
             </span>
             <span [ngClass]="{'not-active': lastItem >= allItems || !isNavigationDisabled}">
-              <span 
-                class="navigation-butts" 
-                (click)="loadItemsForPage('last')" 
+              <span
+                class="navigation-butts"
+                (click)="loadItemsForPage('last')"
                 [ngClass]="{'not-allowed': lastItem >= allItems || !isNavigationDisabled}"
               >
                 <i class="material-icons">last_page</i>
@@ -216,10 +216,10 @@
     <ng-container matColumnDef="resource">
       <th mat-header-cell *matHeaderCellDef class="th_resource label-header">
         <div class="label"><span class="text">Resource</span></div>
-        <button 
-          mat-icon-button 
-          aria-label="More" 
-          class="ar" 
+        <button
+          mat-icon-button
+          aria-label="More"
+          class="ar"
           (click)="toggleFilterRow()"
         >
           <i class="material-icons">
@@ -230,7 +230,7 @@
       </th>
       <td mat-cell *matCellDef="let element" class="th_resource">
         <div class="table-item-wrapper">
-          <span 
+          <span
             class="ellipsis"
             [matTooltip]="element.resourceName || 'N/A'"
             matTooltipPosition="above">
@@ -251,11 +251,11 @@
     <!--   AUDIT FILTER-->
     <ng-container matColumnDef="user-filter">
       <th mat-header-cell *matHeaderCellDef class="filter-row-item">
-        <multi-select-dropdown 
-          *ngIf="filterConfiguration" 
-          (selectionChange)="onUpdate($event)" 
+        <multi-select-dropdown
+          *ngIf="filterConfiguration"
+          (selectionChange)="onUpdate($event)"
           [type]="'users'"
-          [items]="filterConfiguration.users" 
+          [items]="filterConfiguration.users"
           [model]="filterAuditData.users"
         ></multi-select-dropdown>
       </th>
@@ -263,11 +263,11 @@
 
     <ng-container matColumnDef="project-filter">
       <th mat-header-cell *matHeaderCellDef class="filter-row-item">
-        <multi-select-dropdown 
-          *ngIf="filterConfiguration" 
-          (selectionChange)="onUpdate($event)" 
+        <multi-select-dropdown
+          *ngIf="filterConfiguration"
+          (selectionChange)="onUpdate($event)"
           [type]="'projects'"
-          [items]="filterConfiguration.projects" 
+          [items]="filterConfiguration.projects"
           [model]="filterAuditData.projects"
         ></multi-select-dropdown>
       </th>
@@ -277,10 +277,10 @@
       <th mat-header-cell *matHeaderCellDef class="filter-row-item">
         <multi-select-dropdown
           class="audit-resources"
-          *ngIf="filterConfiguration" 
-          (selectionChange)="onUpdate($event)" 
+          *ngIf="filterConfiguration"
+          (selectionChange)="onUpdate($event)"
           [type]="'resources'"
-          [items]="filterConfiguration.resources" 
+          [items]="filterConfiguration.resources"
           [model]="filterAuditData.resources"
         ></multi-select-dropdown>
       </th>
@@ -288,11 +288,11 @@
 
     <ng-container matColumnDef="resource-type-filter">
       <th mat-header-cell *matHeaderCellDef class="filter-row-item">
-        <multi-select-dropdown 
-          *ngIf="filterConfiguration" 
-          (selectionChange)="onUpdate($event)" 
+        <multi-select-dropdown
+          *ngIf="filterConfiguration"
+          (selectionChange)="onUpdate($event)"
           [type]="'resource_types'"
-          [items]="filterConfiguration.resource_types" 
+          [items]="filterConfiguration.resource_types"
           [model]="filterAuditData.resource_types"
         ></multi-select-dropdown>
       </th>
@@ -309,19 +309,19 @@
     <ng-container matColumnDef="filter-buttons" stickyEnd>
       <th mat-header-cell *matHeaderCellDef class="filter-row-item">
         <div class="actions audit-actions">
-          <button 
-            mat-icon-button 
-            class="btn reset" 
-            (click)="resetFilterConfigurations()" 
+          <button
+            mat-icon-button
+            class="btn reset"
+            (click)="resetFilterConfigurations()"
             [disabled]="!isFilterSelected"
           >
             <i class="material-icons">close</i>
           </button>
 
-          <button 
-            mat-icon-button 
-            class="btn apply" 
-            (click)="buildAuditGrid(true)" 
+          <button
+            mat-icon-button
+            class="btn apply"
+            (click)="buildAuditGrid(true)"
             [disabled]="isNavigationDisabled"
           >
             <i class="material-icons">done</i>
@@ -341,9 +341,9 @@
 
     <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true" class="header-row"></tr>
 
-    <tr 
-      [hidden]="!collapseFilterRow" 
-      mat-header-row 
+    <tr
+      [hidden]="!collapseFilterRow"
+      mat-header-row
       *matHeaderRowDef="displayedFilterColumns; sticky: true"
       class="filter-row"
     ></tr>
diff --git a/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.scss b/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.scss
index 555d7ad..7775d3b 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.scss
@@ -288,7 +288,7 @@
   display: flex;
   align-items: center;
 
-  .select-wrapper {
+  .select__wrapper {
     margin-left: 20px;
     width: 80px;
   }
@@ -332,4 +332,4 @@
   border-top: 1px solid #e0e0e0;
   transform: translateY(-1px);
   border-bottom: none;
-}
\ No newline at end of file
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.ts b/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.ts
index 090dcb3..5aa6ffa 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/reports/audit/audit-grid/audit-grid.component.ts
@@ -126,10 +126,10 @@
 
   public openActionInfo(element: AuditItem): void {
     if (element.type === 'GROUP' && element.info.indexOf('role') !== -1) {
-      this.dialog.open(AuditInfoDialogComponent, 
+      this.dialog.open(AuditInfoDialogComponent,
         { data: { element, dialogSize: 'big' }, panelClass: 'modal-xl-m' });
     } else {
-      this.dialog.open(AuditInfoDialogComponent, 
+      this.dialog.open(AuditInfoDialogComponent,
         { data:  {element, dialogSize: 'small' }, panelClass: 'modal-md' });
     }
   }
@@ -149,17 +149,17 @@
       this.lastItem = this.showItemsPrPage;
     } else if (action === 'previous') {
       this.firstItem = this.firstItem - this.showItemsPrPage;
-      this.lastItem = this.lastItem % this.showItemsPrPage === 0 
-        ? this.lastItem - this.showItemsPrPage 
+      this.lastItem = this.lastItem % this.showItemsPrPage === 0
+        ? this.lastItem - this.showItemsPrPage
         : this.lastItem - (this.lastItem % this.showItemsPrPage);
     } else if (action === 'next') {
       this.firstItem = this.firstItem + this.showItemsPrPage;
-      this.lastItem = (this.lastItem + this.showItemsPrPage) > this.allItems 
-        ? this.allItems 
+      this.lastItem = (this.lastItem + this.showItemsPrPage) > this.allItems
+        ? this.allItems
         : this.lastItem + this.showItemsPrPage;
     } else if (action === 'last') {
-      this.firstItem = this.allItems % this.showItemsPrPage === 0 
-        ? this.allItems - this.showItemsPrPage 
+      this.firstItem = this.allItems % this.showItemsPrPage === 0
+        ? this.allItems - this.showItemsPrPage
         : this.allItems - (this.allItems % this.showItemsPrPage) + 1;
       this.lastItem = this.allItems;
     }
@@ -185,12 +185,12 @@
               <h4 class="modal-title">{{data.element.action | convertaction}}</h4>
               <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
           </header>
-          <div 
-            mat-dialog-content 
-            class="content audit-info-content" 
+          <div
+            mat-dialog-content
+            class="content audit-info-content"
             [ngClass]="{'pb-40': actionList[0].length > 1}"
           >
-            <mat-list 
+            <mat-list
               *ngIf="actionList[0].length > 1 && data.element.action !== 'FOLLOW_LINK'
                     || data.element.info.indexOf('Update quota') !== -1;else message"
             >
@@ -203,9 +203,9 @@
 
                 <div class="scrolling-content mat-list-wrapper" id="scrolling">
                   <mat-list-item class="list-item" *ngFor="let action of actionList">
-                    <div 
-                      *ngIf="(data.element.action === 'upload' && action[0] === 'File(s)') 
-                          || (data.element.action === 'download' && action[0] === 'File(s)');else multiAction" 
+                    <div
+                      *ngIf="(data.element.action === 'upload' && action[0] === 'File(s)')
+                          || (data.element.action === 'download' && action[0] === 'File(s)');else multiAction"
                       class="info-item-title"
                     >
                       File
@@ -213,12 +213,12 @@
                     <ng-template #multiAction>
                        <div class="info-item-title" [ngClass]="{'same-column-width': data.dialogSize === 'small'}">{{action[0]}}</div>
                     </ng-template>
-                    <div 
-                      class="info-item-data" 
-                      [ngClass]="{'same-column-width': data.dialogSize === 'small'}" 
+                    <div
+                      class="info-item-data"
+                      [ngClass]="{'same-column-width': data.dialogSize === 'small'}"
                       *ngIf="action[0] === 'File(s)'"
                     >
-                      <div 
+                      <div
                         class="file-description ellipsis"
                         *ngFor="let description of action[1]?.split(',')"
                         [matTooltip]="description"
@@ -228,7 +228,7 @@
                       </div>
                     </div>
                     <div class="info-item-data" [ngClass]="{'same-column-width': data.dialogSize === 'small'}" *ngIf="action[0] !== 'File(s)'">
-                       <div 
+                       <div
                           *ngFor="let description of action[1]?.split(',')"
                           [matTooltip]="description"
                           class="ellipsis"
@@ -301,6 +301,7 @@
     .message-wrapper{min-height: 70px;; display: flex; align-items: center}
     .mat-list-wrapper{padding-top: 5px;}
     .list-item{color: #718ba6; height: auto; line-height: 20px; font-size: 14px}
+    .list-item:not(:last-child) { border-bottom:1px solid #edf1f5;}
     .info-item-title{width: 40%; padding: 10px 0;font-size: 14px;}
     .info-item-quota{width: 30%; padding: 10px 0;font-size: 14px;}
     .list-header {padding-top: 5px;}
@@ -353,4 +354,4 @@
     }
     this.actionList = data.element.info.split('\n').map(v => v.split(':')).filter(v => v[0] !== '');
   }
-}
\ No newline at end of file
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.html b/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.html
index b522b07..2bd8a46 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.html
@@ -49,7 +49,7 @@
           <mat-icon [ngClass]="{'highlight': isMaxRight | async }">keyboard_arrow_right</mat-icon>
         </button>
       </div>
-      <div class="totaL-item strong" >
+      <div class="totaL-item strong" *ngIf="reportData?.length">
         Total <span>{{fullReport.total_cost | localcurrency}}</span>
       </div>
     </div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.ts b/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.ts
index 513ac45..9e45d91 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/reports/reporting/reporting-grid/reporting-grid.component.ts
@@ -62,13 +62,13 @@
   isFiltered: boolean = false;
   active: object = {};
   displayedColumns: string[] = [
-    'name', 'user', 'project', 
-    'type', 'status', 'shape', 
+    'name', 'user', 'project',
+    'type', 'status', 'shape',
     'service', 'empty', 'charge'
   ];
   displayedFilterColumns: string[] = [
-    'name-filter', 'user-filter', 'project-filter', 
-    'type-filter', 'status-filter', 'shape-filter',  
+    'name-filter', 'user-filter', 'project-filter',
+    'type-filter', 'status-filter', 'shape-filter',
     'service-filter', 'empty-filter', 'actions'
   ];
   filtered: any;
@@ -106,7 +106,7 @@
 
   ngOnInit() {
     this.userAgentIndex = window.navigator.userAgent.indexOf('Firefox');
-    
+
     window.setTimeout(() => {
       this.isScrollButtonsVisible = this.tableWrapper.nativeElement.offsetWidth - this.table._elementRef.nativeElement.offsetWidth < 0;
       this.checkMaxRight();
@@ -128,7 +128,6 @@
 
   refreshData(fullReport, report) {
     this.reportData = [...report];
-    console.log(fullReport);
     this.fullReport = fullReport;
     this.checkFilters();
   }
@@ -168,7 +167,7 @@
         return 0;
       });
     }
-    
+
     this.refreshData(this.fullReport, report);
     this.removeSorting();
     this.active[sortItem + direction] = true;
@@ -223,7 +222,7 @@
     const arg = this.tableWrapper.nativeElement.offsetWidth +
       this.tableWrapper.nativeElement.scrollLeft + 2 <= this.table._elementRef.nativeElement.offsetWidth;
     return this.isMaxRight.next(arg);
-    
+
   }
 
   public onFilterNameUpdate(targetElement: any) {
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.ts
index 010e5d2..05f822f 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/bucket-browser/bucket-browser.component.ts
@@ -127,9 +127,8 @@
   }
 
   public toggleSelectedFile(file, type): void {
-    console.log(file, type);
-    type === 'file' 
-      ? file.isSelected = !file.isSelected 
+    type === 'file'
+      ? file.isSelected = !file.isSelected
       : file.isFolderSelected = !file.isFolderSelected;
     this.selected = this.folderItems.filter(item => item.isSelected);
     this.selectedFolderForAction = this.folderItems.filter(item => item.isFolderSelected);
@@ -260,8 +259,8 @@
       this.objectPath = event.pathObject;
       this.path = event.path;
       this.originFolderItems = this.folderItems.map(v => v);
-      this.pathInsideBucket = this.path.indexOf('/') !== -1 
-        ? this.path.slice(this.path.indexOf('/') + 1) + '/' 
+      this.pathInsideBucket = this.path.indexOf('/') !== -1
+        ? this.path.slice(this.path.indexOf('/') + 1) + '/'
         : '';
       this.folderItems.forEach(item => item.isSelected = false);
     }
@@ -327,7 +326,7 @@
       if (!file) {
         file = waitUploading[0];
       }
-      
+
       file.status = 'uploading';
       this.isFileUploading = this.addedFiles.some(v => v.status === 'uploading');
       this.isQueueFull = this.addedFiles.some(v => v.status === 'waiting');
@@ -350,7 +349,7 @@
               this.sendFile(this.addedFiles.find(v => v.status === 'waiting'));
               this.bucketDataService.refreshBucketdata(this.bucketName, this.endpoint);
             }
-          }, 
+          },
           error => {
             window.clearInterval(file.interval);
             file.status = 'failed';
@@ -412,7 +411,7 @@
                 selected[0].progress = 0;
               }, 1000);
             }
-          }, 
+          },
           error => {
             this.toastr.error(error.message || 'File downloading error!', 'Oops!');
             selected[0]['isDownloading'] = false;
@@ -461,7 +460,7 @@
   public copyPath(): void {
     const selected = this.folderItems.filter(item => item.isSelected || item.isFolderSelected)[0];
     const pathToItem = `${this.pathInsideBucket}${selected.item}${selected.isFolderSelected ? '/' : ''}`;
-    
+
     const cloud = this.getCloud();
     const protocol = HelpUtils.getBucketProtocol(cloud);
     if (cloud !== 'azure') {
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.html
index b0d1eb6..d8f1b00 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.html
@@ -130,7 +130,7 @@
           <div class="m-top-10">
             <p *ngFor="let item of resource.computational_url" class="ellipsis flex" (mouseleave)="hideCopyIcon()">
               <span class="strong spark-url-desc">{{ item.description }}:</span>&nbsp;
-              <a 
+              <a
                 (click)="logAction(resource, environment, 'follow')"
                  href="{{item.url}}"
                  target="_blank"
@@ -145,8 +145,8 @@
               <span
                 (click)="logAction(resource, environment, 'copy');$event.stopPropagation()"
                 *ngIf="isCopyIconVissible[item.description]"
-                [matTooltip]="isCopied ? 'Copy ' + item.description + (item.description.indexOf('url')  === -1 ? ' url' : ''): 'Copied'" 
-                matTooltipPosition="above" 
+                [matTooltip]="isCopied ? 'Copy ' + item.description + (item.description.indexOf('url')  === -1 ? ' url' : ''): 'Copied'"
+                matTooltipPosition="above"
                 class="copy-icon-wrapper"
               >
                 <span  class="link-icon" (click)="copyLink(item.url)" >
@@ -156,52 +156,52 @@
             </p>
           </div>
         </div>
-        <div 
-          class="checkbox-group" 
-          *ngIf="resource.image === 'docker.datalab-dataengine'
-              && resource.status === 'running'
-              && environment.image !== 'docker.datalab-zeppelin'
-              && environment.image !== 'docker.datalab-superset'
-              && environment.image !== 'docker.datalab-jupyterlab'"
-        >
-          <label>
-            <input #configurationNode type="checkbox" (change)="selectConfiguration()"/> Cluster configurations
-          </label>
-          <div class="checkbox-group">
-            <form [formGroup]="configurationForm" novalidate>
-              <div class="config-details" [ngClass]="{ show: configuration?.nativeElement['checked'] || false }">
-                <textarea 
-                  formControlName="configuration_parameters" 
-                  placeholder="Cluster configuration template, JSON"
-                  data-gramm_editor="false"
-                ></textarea>
-                <span class="danger_color"
-                  *ngIf="!configurationForm.controls.configuration_parameters.valid 
-                      && configurationForm.controls['configuration_parameters'].dirty">
-                      Configuration parameters is not in a valid format
-                </span>
-              </div>
-            </form>
-          </div>
-        </div>
-        <div *ngIf="environment.image === 'docker.datalab-zeppelin' && resource.status === 'running'">
-          <small>Spark default configuration for Apache Zeppelin can not be changed from DataLab UI. 
-            Currently it can be done directly through Apache Zeppelin interpreter menu.
-              For more details please refer for Apache Zeppelin 
-              <a href="https://zeppelin.apache.org/docs/0.9.0/usage/interpreter/overview.html" target="_blank">official
-                  documentation</a>.
-          </small>
-        </div>
+<!--        <div-->
+<!--          class="checkbox-group"-->
+<!--          *ngIf="resource.image === 'docker.datalab-dataengine'-->
+<!--              && resource.status === 'running'-->
+<!--              && environment.image !== 'docker.datalab-zeppelin'-->
+<!--              && environment.image !== 'docker.datalab-superset'-->
+<!--              && environment.image !== 'docker.datalab-jupyterlab'"-->
+<!--        >-->
+<!--          <label>-->
+<!--            <input #configurationNode type="checkbox" (change)="selectConfiguration()"/> Cluster configurations-->
+<!--          </label>-->
+<!--          <div class="checkbox-group">-->
+<!--            <form [formGroup]="configurationForm" novalidate>-->
+<!--              <div class="config-details" [ngClass]="{ show: configuration?.nativeElement['checked'] || false }">-->
+<!--                <textarea-->
+<!--                  formControlName="configuration_parameters"-->
+<!--                  placeholder="Cluster configuration template, JSON"-->
+<!--                  data-gramm_editor="false"-->
+<!--                ></textarea>-->
+<!--                <span class="danger_color"-->
+<!--                  *ngIf="!configurationForm.controls.configuration_parameters.valid-->
+<!--                      && configurationForm.controls['configuration_parameters'].dirty">-->
+<!--                      Configuration parameters is not in a valid format-->
+<!--                </span>-->
+<!--              </div>-->
+<!--            </form>-->
+<!--          </div>-->
+<!--        </div>-->
+<!--        <div *ngIf="environment.image === 'docker.datalab-zeppelin' && resource.status === 'running'">-->
+<!--          <small>Spark default configuration for Apache Zeppelin can not be changed from DataLab UI.-->
+<!--            Currently it can be done directly through Apache Zeppelin interpreter menu.-->
+<!--              For more details please refer for Apache Zeppelin-->
+<!--              <a href="https://zeppelin.apache.org/docs/0.9.0/usage/interpreter/overview.html" target="_blank">official-->
+<!--                  documentation</a>.-->
+<!--          </small>-->
+<!--        </div>-->
         <div class="text-center m-top-30" *ngIf="configuration?.nativeElement['checked'] || false">
-          <button 
-            mat-raised-button type="button" 
-            (click)="dialogRef.close()" 
+          <button
+            mat-raised-button type="button"
+            (click)="dialogRef.close()"
             class="butt action"
           >
             Cancel
           </button>
-          <button 
-            mat-raised-button type="submit" 
+          <button
+            mat-raised-button type="submit"
             [disabled]="!configurationForm.valid"
             class="butt butt-success action"
             [ngClass]="{'not-allowed': !configurationForm.valid}"
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.ts
index 1e6526b..1c6842c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/cluster-details.component.ts
@@ -74,6 +74,7 @@
     if (this.resource.image === 'docker.datalab-dataengine') {
       this.getClusterConfiguration();
     }
+    console.log(this.resource);
   }
 
   public isEllipsisActive($event): void {
@@ -139,9 +140,9 @@
     };
 
     this.auditService.sendDataToAudit(
-      { 
-        resource_name: resource.computational_name, 
-        info: JSON.stringify(clusterInfo), 
+      {
+        resource_name: resource.computational_name,
+        info: JSON.stringify(clusterInfo),
         type: 'COMPUTE'
       }
     ).subscribe();
@@ -154,7 +155,7 @@
   public showCopyIcon(element) {
     this.isCopyIconVissible[element] = true;
   }
-  
+
   public hideCopyIcon() {
     for (const key in this.isCopyIconVissible) {
       this.isCopyIconVissible[key] = false;
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html
index 5e9095c..dc516ad 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.html
@@ -27,18 +27,22 @@
       <form [formGroup]="resourceForm" *ngIf="clusterTypes.length && resourceForm; else placeholder">
         <div class="form-wrapper">
           <div class="col">
-            <div class="control-group" *ngIf="PROVIDER !== 'azure'" [hidden]="clusterTypes.length === 1">
+            <div
+              class="control-group"
+              *ngIf="(clusterTypes | isElementAvailable : hasHDInside) || this.PROVIDER !== providerList.azure"
+              [hidden]="clusterTypes.length === 1"
+            >
               <label class="label">Select cluster type</label>
               <div class="control selector-wrapper">
                 <mat-form-field>
-                  <mat-select 
-                    formControlName="template_name" 
+                  <mat-select
+                    formControlName="template_name"
                     disableOptionCentering
                     panelClass="scrolling"
                     placeholder="Select cluster type"
                   >
-                    <mat-option 
-                      *ngFor="let type of clusterTypes" 
+                    <mat-option
+                      *ngFor="let type of clusterTypes"
                       [value]="type.template_name"
                       (click)="selectImage(type)"
                     >
@@ -60,12 +64,12 @@
               <div class="control">
                 <input
                   [class.danger_field]="!resourceForm?.controls['cluster_alias_name'].valid
-                        && resourceForm?.controls['cluster_alias_name'].dirty 
+                        && resourceForm?.controls['cluster_alias_name'].dirty
                         && resourceForm?.controls['cluster_alias_name'].hasError('duplication')"
-                  type="text" 
-                  class="form-control" 
+                  type="text"
+                  class="form-control"
                   placeholder="Enter cluster alias"
-                  formControlName="cluster_alias_name" 
+                  formControlName="cluster_alias_name"
                 />
                 <span class="error" *ngIf="resourceForm?.controls['cluster_alias_name'].hasError('user-duplication')">
                   You have cluster with this name in current project.
@@ -73,9 +77,9 @@
                 <span class="error" *ngIf="resourceForm?.controls['cluster_alias_name'].hasError('other-user-duplication')">
                   Other user has cluster with this name in current project.
                 </span>
-                <span 
-                  class="error" 
-                  *ngIf="resourceForm?.controls['cluster_alias_name'].hasError('maxlength') 
+                <span
+                  class="error"
+                  *ngIf="resourceForm?.controls['cluster_alias_name'].hasError('maxlength')
                     && !resourceForm?.controls['cluster_alias_name'].hasError('pattern')"
                 >
                   Cluster name cannot be longer than {{maxClusterNameLength}} characters.
@@ -93,7 +97,7 @@
                 <mat-form-field>
                   <mat-label>Select instance size</mat-label>
                   <mat-select panelClass="scrolling" formControlName="shape_master" disableOptionCentering>
-                    <mat-optgroup 
+                    <mat-optgroup
                       *ngFor="let item of (selectedImage.computation_resources_shapes | keys)"
                       [label]="item.key | underscoreless"
                     >
@@ -114,12 +118,12 @@
             <div class="control-group" *ngIf="selectedImage?.image">
               <label class="label">Total instance number</label>
               <div class="control">
-                <input 
-                  type="number" 
-                  class="form-control" 
-                  min="{{minInstanceNumber}}" 
+                <input
+                  type="number"
+                  class="form-control"
+                  min="{{minInstanceNumber}}"
                   max="{{maxInstanceNumber}}"
-                  formControlName="instance_number" (keypress)="CheckUtils.isNumberKey($event)" 
+                  formControlName="instance_number" (keypress)="CheckUtils.isNumberKey($event)"
                 />
                 <span class="error" *ngIf="!resourceForm?.controls.instance_number.valid">
                   <span>Only integer values greater than or equal to {{ minInstanceNumber }} and less than
@@ -128,7 +132,10 @@
               </div>
             </div>
 
-            <div class="control-group" *ngIf="PROVIDER !== 'azure'" [hidden]="!selectedImage.templates.length">
+            <div class="control-group"
+                 *ngIf="(clusterTypes | isElementAvailable : hasHDInside) || PROVIDER !== providerList.azure"
+                 [hidden]="!selectedImage.templates.length"
+            >
               <label class="label">Select template</label>
               <div class="control selector-wrapper">
                 <mat-form-field>
@@ -153,13 +160,13 @@
                 <mat-form-field>
                   <mat-label>Select instance size</mat-label>
                   <mat-select panelClass="scrolling" formControlName="shape_slave" disableOptionCentering>
-                    <mat-optgroup 
+                    <mat-optgroup
                       *ngFor="let item of (selectedImage.computation_resources_shapes | keys)"
                       [label]="item.key | underscoreless"
                     >
-                      <mat-option 
-                        *ngFor="let list_item of item.value" 
-                        [value]="list_item.Type" 
+                      <mat-option
+                        *ngFor="let list_item of item.value"
+                        [value]="list_item.Type"
                         (click)="clearGpuType('slave')"
                       >
                         <strong class="highlight icon-label">{{ list_item.Size }}</strong> {{
@@ -186,7 +193,7 @@
             <div class="col">
               <div class="control-group">
                 <label class="label">Master GPU type</label>
-                <div 
+                <div
                   class="control selector-wrapper"
                   [ngClass]="{ 'not-active' : !resourceForm.controls['shape_master'].value}"
                   [matTooltip]="'Please, select master instance size.'"
@@ -195,7 +202,7 @@
                   [matTooltipDisabled]="!!resourceForm.controls['shape_master'].value.length"
                 >
                   <mat-form-field>
-                    <mat-select 
+                    <mat-select
                       formControlName="master_GPU_type" disableOptionCentering
                       placeholder="Select master GPU type"
                       [disabled]="!resourceForm.controls['shape_master'].value"
@@ -215,7 +222,7 @@
               </div>
               <div class="control-group">
                 <label class="label">Master GPU сount</label>
-                <div 
+                <div
                   class="control selector-wrapper"
                   [ngClass]="{'not-active': !resourceForm.controls['master_GPU_type'].value}"
                   [matTooltip]="'Please, select master GPU type.'"
@@ -242,7 +249,7 @@
             <div class="col">
               <div class="control-group">
                 <label class="label">Slave GPU type</label>
-                <div 
+                <div
                   class="control selector-wrapper"
                   [ngClass]="{ 'not-active': !resourceForm.controls['shape_slave'].value}"
                   [matTooltip]="'Please, select slave instance size.'"
@@ -271,7 +278,7 @@
 
               <div class="control-group">
                 <label class="label">Slave GPU сount</label>
-                <div 
+                <div
                   class="control selector-wrapper"
                   [ngClass]="{'not-active': !resourceForm.controls['slave_GPU_type'].value}"
                   [matTooltip]="'Please, select slave GPU type.'"
@@ -298,7 +305,7 @@
             </div>
           </div>
         </div>
-        <div 
+        <div
           class="preemptible checkbox-group control-group"
           *ngIf="PROVIDER === 'gcp' && selectedImage?.image === 'docker.datalab-dataengine-service'"
         >
@@ -308,14 +315,14 @@
             </div>
             <span class="pl-5">Preemptible node</span>
           </div>
-          <div 
-            *ngIf="isSelected.preemptible" 
+          <div
+            *ngIf="isSelected.preemptible"
             class="preemptible-details control"
             [ngClass]="{ show: isSelected.preemptible}"
           >
-            <input 
-              type="text" 
-              class="form-control" 
+            <input
+              type="text"
+              class="form-control"
               formControlName="preemptible_instance_number"
               (keypress)="CheckUtils.isNumberKey($event)"
               (keydown.arrowup)="preemptibleCounter($event, 'increment')"
@@ -333,37 +340,38 @@
 
         <div class="checkbox-group control-group m-top-15" *ngIf="PROVIDER === 'aws'" [hidden]="!selectedImage.templates.length">
           <div class="d-flex cursor-pointer label" (click)="addAdditionalParams('spotInstances')">
-            <div class="empty-checkbox ml-10" [ngClass]="{'checked': isSelected.spotInstances}" (click)="selectSpotInstances()">
-              <span class="checked-checkbox" *ngIf="isSelected.spotInstances"></span>
+            <div class="empty-checkbox ml-10" [ngClass]="{'checked': instanceSpot}" (click)="selectSpotInstances()">
+              <span class="checked-checkbox" *ngIf="instanceSpot"></span>
             </div>
-            <span class="pl-5">Spot instance</span><span [hidden]="!isSelected.spotInstances">&nbsp;bid, %</span>
+            <span class="pl-5">Spot instance</span><span [hidden]="!instanceSpot">&nbsp;bid, %</span>
           </div>
-          <div 
-            class="control spot-details" 
-            [ngClass]="{ show: isSelected.spotInstances }"
-            *ngIf="isSelected.spotInstances"
+          <div
+            class="control spot-details"
+            [ngClass]="{ show: instanceSpot }"
+            *ngIf="instanceSpot"
           >
-            <input 
-              type="number" 
-              class="form-control" 
-              step="5" 
-              min="{{minSpotPrice}}" 
+            <input
+              type="number"
+              class="form-control"
+              step="5"
+              min="{{minSpotPrice}}"
               max="{{maxSpotPrice}}"
-              formControlName="instance_price" 
+              formControlName="instance_price"
               (keypress)="CheckUtils.isNumberKey($event)"
             />
             <span class="error error-bottom" *ngIf="!resourceForm?.controls.instance_price.valid">
               Only integer values greater than or equal to {{minSpotPrice}} and less than {{maxSpotPrice}} are allowed.
             </span>
           </div>
-          <span class="info ml-10" *ngIf="isSelected.spotInstances">When the current Spot price
+          <span class="info ml-10" *ngIf="instanceSpot">When the current Spot price
             rises above your bid price, the Spot instance is reclaimed by AWS so that it can be given to another
             customer. Make sure to backup your data on periodic basis.
           </span>
         </div>
-        <div 
+        <div
           class="checkbox-group control-group m-top-10"
-          [hidden]="PROVIDER === 'gcp' && selectedImage?.image === 'docker.datalab-dataengine-service'"
+          [hidden]="PROVIDER === 'gcp' && selectedImage?.image === 'docker.datalab-dataengine-service'
+           || templateNameControl.value === templateName.hdInsight"
           *ngIf="notebook_instance?.image !== 'docker.datalab-zeppelin'"
         >
           <div class="d-flex cursor-pointer label" (click)="addAdditionalParams('configuration')">
@@ -372,9 +380,9 @@
             </div>
             <span class="pl-5">Cluster configurations</span>
           </div>
-          <div 
-            class="config-link" 
-            *ngIf="(isSelected.configuration) 
+          <div
+            class="config-link"
+            *ngIf="(isSelected.configuration)
               && selectedImage?.image === 'docker.datalab-dataengine-service'
               && PROVIDER === 'aws'"
           >
@@ -386,14 +394,14 @@
         </div>
         <div class="checkbox-group ml-10">
           <div class="config-details" [ngClass]="{ show: isSelected.configuration }">
-            <textarea 
-              formControlName="configuration_parameters" 
+            <textarea
+              formControlName="configuration_parameters"
               placeholder="Cluster configuration template, JSON"
               data-gramm_editor="false">
             </textarea>
-            <span 
+            <span
               class="error"
-              *ngIf="!resourceForm?.controls.configuration_parameters.valid 
+              *ngIf="!resourceForm?.controls.configuration_parameters.valid
                 && resourceForm?.controls['configuration_parameters'].dirty"
             >
               Configuration parameters is not in a valid format.
@@ -410,25 +418,25 @@
           </small>
         </div>
         <div class="text-center m-top-30">
-          <button 
-            mat-raised-button 
-            type="button" 
-            (click)="dialogRef.close()" 
+          <button
+            mat-raised-button
+            type="button"
+            (click)="dialogRef.close()"
             class="butt action"
           >
             Cancel
           </button>
-          <button 
-            mat-raised-button 
-            type="button" 
-            [disabled]="!resourceForm?.valid 
-              || (!resourceForm.value.shape_slave) 
-              || (selectedImage?.image === 'docker.datalab-dataengine-service' && !resourceForm.value.version)"
-            (click)="createComputationalResource(resourceForm.value)" 
-            class="butt butt-success action"
-            [ngClass]="{'not-allowed': !resourceForm?.valid 
-              || (selectedImage?.image === 'docker.datalab-dataengine-service' && !resourceForm.value.shape_slave) 
+          <button
+            mat-raised-button
+            [ngClass]="{'not-allowed': !resourceForm?.valid
+              || (selectedImage?.image === 'docker.datalab-dataengine-service' && !resourceForm.value.shape_slave)
               || (selectedImage?.image === 'docker.datalab-dataengine-service' && !resourceForm.value.version) }"
+            [disabled]="!resourceForm?.valid
+              || (!resourceForm.value.shape_slave)
+              || (selectedImage?.image === 'docker.datalab-dataengine-service' && !resourceForm.value.version)"
+            type="button"
+            (click)="createComputationalResource(resourceForm.value)"
+            class="butt butt-success action"
           >
             Create
           </button>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts
index 6fd9991..41a5178 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.ts
@@ -17,17 +17,21 @@
  * under the License.
  */
 
-import { Component, OnInit, Inject, ChangeDetectorRef } from '@angular/core';
-import {FormGroup, FormBuilder, Validators} from '@angular/forms';
-import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { ChangeDetectorRef, Component, Inject, OnInit } from '@angular/core';
+import { FormBuilder, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
 import { ToastrService } from 'ngx-toastr';
 
 import { ComputationalResourceModel } from './computational-resource-create.model';
 import { UserResourceService } from '../../../core/services';
-import { HTTP_STATUS_CODES, PATTERNS, CheckUtils, SortUtils, HelpUtils } from '../../../core/util';
+import { CheckUtils, HelpUtils, HTTP_STATUS_CODES, PATTERNS, SortUtils } from '../../../core/util';
 
 import { DICTIONARY } from '../../../../dictionary/global.dictionary';
 import { CLUSTER_CONFIGURATION } from './cluster-configuration-templates';
+import { DockerImageName } from '../../../core/models';
+import { ImageTemplateName } from '../../../core/configs/image-template-name';
+import { ComputationalTemplate } from './computational.resource.model';
+import { Providers } from '../../../core/configs/providers';
 
 @Component({
   selector: 'computational-resource-create-dialog',
@@ -40,6 +44,8 @@
   readonly DICTIONARY = DICTIONARY;
   readonly CLUSTER_CONFIGURATION = CLUSTER_CONFIGURATION;
   readonly CheckUtils = CheckUtils;
+  readonly providerList: typeof Providers = Providers;
+  readonly templateName: typeof ImageTemplateName = ImageTemplateName;
 
   notebook_instance: any;
   resourcesList: any;
@@ -78,7 +84,7 @@
     private _ref: ChangeDetectorRef,
   ) { }
 
-  ngOnInit() {
+  ngOnInit(): void {
     this.loading = true;
     this.notebook_instance = this.data.notebook;
     this.resourcesList = this.data.full_list;
@@ -86,7 +92,7 @@
     this.getTemplates(this.notebook_instance.project, this.notebook_instance.endpoint, this.notebook_instance.cloud_provider);
   }
 
-  public selectImage($event) {
+  public selectImage($event): void {
     this.selectedImage = $event;
     this.filterShapes();
     this.getComputationalResourceLimits();
@@ -97,22 +103,25 @@
   }
 
   public selectSpotInstances(): void {
-    if (this.isSelected.spotInstances) {
+    if (!this.instanceSpot) {
       this.spotInstance = true;
-      this.resourceForm.controls['instance_price'].setValue(50);
+      this.resourceForm.controls['emr_slave_instance_spot'].patchValue(true);
+      this.resourceForm.controls['instance_price'].enable();
+      this.resourceForm.controls['instance_price'].patchValue(50);
     } else {
       this.spotInstance = false;
-      this.resourceForm.controls['instance_price'].setValue(0);
+      this.resourceForm.controls['emr_slave_instance_spot'].patchValue(false);
+      this.resourceForm.controls['instance_price'].disable();
     }
   }
 
-  public selectPreemptibleNodes(addPreemptible) {
+  public selectPreemptibleNodes(addPreemptible): void {
     if (addPreemptible) {
       this.resourceForm.controls['preemptible_instance_number'].setValue(this.minPreemptibleInstanceNumber);
     }
   }
 
-  public selectConfiguration() {
+  public selectConfiguration(): void {
     if (this.isSelected.configuration) {
       const template = (this.selectedImage.image === 'docker.datalab-dataengine-service')
         ? CLUSTER_CONFIGURATION.EMR
@@ -139,22 +148,27 @@
     return false;
   }
 
-  public createComputationalResource(data) {
+  public createComputationalResource(data): void {
     this.model.createComputationalResource(data, this.selectedImage, this.notebook_instance,
-      this.spotInstance, this.PROVIDER.toLowerCase(), this.isSelected.gpu)
+      this.PROVIDER.toLowerCase(), this.isSelected.gpu)
       .subscribe(
         (response: any) => {
           if (response.status === HTTP_STATUS_CODES.OK) this.dialogRef.close(true);
-        }, 
+        },
         error => this.toastr.error(error.message, 'Oops!')
       );
   }
 
+  public hasHDInside(templateList: ComputationalTemplate[]): boolean {
+    return  templateList.some(({template_name}) => template_name === ImageTemplateName.hdInsight);
+  }
+
   private initFormModel(): void {
     this.resourceForm = this._fb.group({
       template_name: ['', [Validators.required]],
       version: [''],
       shape_master: ['', Validators.required],
+      emr_slave_instance_spot: '',
       shape_slave: [''],
       cluster_alias_name: ['', [
         Validators.required, Validators.pattern(PATTERNS.namePattern),
@@ -165,7 +179,7 @@
       preemptible_instance_number: [0,
         Validators.compose([Validators.pattern(PATTERNS.integerRegex),
         this.validPreemptibleRange.bind(this)])],
-      instance_price: [0, [this.validInstanceSpotRange.bind(this)]],
+      instance_price: [0, [this.validInstanceSpotRange()]],
       configuration_parameters: ['', [this.validConfiguration.bind(this)]],
       custom_tag: [this.notebook_instance.tags.custom_tag],
       master_GPU_type: [''],
@@ -186,17 +200,18 @@
       this.minInstanceNumber = this.selectedImage.limits[activeImage.total_instance_number_min];
       this.maxInstanceNumber = this.selectedImage.limits[activeImage.total_instance_number_max];
 
-      if (this.PROVIDER === 'gcp' && this.selectedImage.image === 'docker.datalab-dataengine-service') {
+      if (this.PROVIDER === 'gcp' && this.selectedImage.image === DockerImageName.dataEngineService) {
         this.maxInstanceNumber = this.selectedImage.limits[activeImage.total_instance_number_max] - 1;
         this.minPreemptibleInstanceNumber = this.selectedImage.limits.min_dataproc_preemptible_instance_count;
       }
 
-      if (this.PROVIDER === 'aws' && this.selectedImage.image === 'docker.datalab-dataengine-service') {
+      if (this.PROVIDER === 'aws' && this.selectedImage.image === DockerImageName.dataEngineService) {
         this.minSpotPrice = this.selectedImage.limits.min_emr_spot_instance_bid_pct;
         this.maxSpotPrice = this.selectedImage.limits.max_emr_spot_instance_bid_pct;
 
         this.isSelected.spotInstances = true;
-        this.selectSpotInstances();
+        this.resourceForm.controls['emr_slave_instance_spot'].setValue(true);
+        this.resourceForm.controls['instance_price'].setValue(50);
       }
 
       this.resourceForm.controls['instance_number'].setValue(this.minInstanceNumber);
@@ -239,18 +254,21 @@
     }
   }
 
-  private validInstanceSpotRange(control) {
-    if (this.isSelected.spotInstances) {
-      return this.isSelected.spotInstances
-        ? (control.value >= this.minSpotPrice && control.value <= this.maxSpotPrice ? null : { valid: false })
-        : control.value;
-    }
+  private validInstanceSpotRange(): ValidatorFn {
+    return (control: FormControl) => {
+      if (!this.isSelected.spotInstances) {
+        return null;
+      }
+      return control.value >= this.minSpotPrice && control.value <= this.maxSpotPrice
+        ? null
+        : { valid: false };
+    };
   }
 
   private validConfiguration(control) {
     if (this.isSelected.configuration) {
-      return this.isSelected.configuration 
-        ? (control.value && control.value !== null && CheckUtils.isJSON(control.value) ? null : { valid: false })
+      return this.isSelected.configuration
+        ? (control.value && CheckUtils.isJSON(control.value) ? null : { valid: false })
         : null;
     }
   }
@@ -265,12 +283,12 @@
     }
   }
 
-  private getTemplates(project, endpoint, provider) {
+  private getTemplates(project, endpoint, provider): void {
     this.userResourceService.getComputationalTemplates(project, endpoint, provider).subscribe(
-      clusterTypes => {
-        this.clusterTypes = clusterTypes.templates;
-        this.userComputations = clusterTypes.user_computations;
-        this.projectComputations = clusterTypes.project_computations;
+      ({templates, user_computations, project_computations}) => {
+        this.clusterTypes = templates;
+        this.userComputations = user_computations;
+        this.projectComputations = project_computations;
 
         this.clusterTypes.forEach((cluster, index) => this.clusterTypes[index].computation_resources_shapes =
           SortUtils.shapesSort(cluster.computation_resources_shapes));
@@ -291,8 +309,7 @@
     let filtered;
 
     const reduceShapes = (obj, key) => {
-      obj[key] = this.selectedImage.computation_resources_shapes[key];
-      return obj;
+      return {...obj, [key]: this.selectedImage.computation_resources_shapes[key]};
     };
 
     const filteredShapeKeys = Object.keys(
@@ -307,8 +324,7 @@
     ) {
       filtered = filterShapes(key => allowed.includes(key));
       if (this.PROVIDER !== 'azure') {
-        const images = this.clusterTypes.filter(image => image.image === 'docker.datalab-dataengine');
-        this.clusterTypes = images;
+        this.clusterTypes = this.clusterTypes.filter(image => image.image === 'docker.datalab-dataengine');
         this.selectedImage = this.clusterTypes[0];
       }
     } else if (this.notebook_instance.template_name.toLowerCase().indexOf('jupyter notebook') !== -1 &&
@@ -373,4 +389,11 @@
       this.resourceForm.controls['slave_GPU_count'].setValue('');
     }
   }
+
+  get instanceSpot() {
+    return this.resourceForm.controls['emr_slave_instance_spot'].value;
+  }
+  get templateNameControl(): FormControl {
+    return  this.resourceForm.get('template_name') as FormControl;
+  }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create.model.ts b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create.model.ts
index 596f8ea..4efa440 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create.model.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create.model.ts
@@ -28,11 +28,23 @@
 
   constructor(private userResourceService: UserResourceService) { }
 
-  public createComputationalResource(parameters, image, env, spot, provider, gpu?): Observable<{}> {
+  public createComputationalResource(parameters, image, env, provider, gpu?): Observable<{}> {
     const config = parameters.configuration_parameters ? JSON.parse(parameters.configuration_parameters) : null;
+    const requestObj = this.createRequestObject(parameters, image, env, provider, config, gpu);
+    const dataEngineServiceCondition = (provider === 'aws' && image.image === 'docker.datalab-dataengine-service')
+      || (provider === 'gcp' && image.image === 'docker.datalab-dataengine-service')
+      || (provider === 'azure' && image.template_name === 'HDInsight cluster');
 
+    if (dataEngineServiceCondition) {
+      return this.userResourceService.createComputationalResource_DataengineService(requestObj, provider);
+    } else {
+      return this.userResourceService.createComputationalResource_Dataengine(requestObj, provider);
+    }
+  }
+
+  private createRequestObject(parameters, image, env, provider, config, gpu?) {
     if (provider === 'aws' && image.image === 'docker.datalab-dataengine-service') {
-      return this.userResourceService.createComputationalResource_DataengineService({
+      return {
         name: parameters.cluster_alias_name,
         emr_instance_count: parameters.instance_number,
         emr_master_instance_type: parameters.shape_master,
@@ -41,14 +53,14 @@
         notebook_name: env.name,
         image: image.image,
         template_name: image.template_name,
-        emr_slave_instance_spot: spot,
+        emr_slave_instance_spot: parameters.emr_slave_instance_spot,
         emr_slave_instance_spot_pct_price: parameters.instance_price,
         config: config,
         project: env.project,
         custom_tag: parameters.custom_tag
-      }, provider);
+      };
     } else if (provider === 'gcp' && image.image === 'docker.datalab-dataengine-service') {
-      return this.userResourceService.createComputationalResource_DataengineService({
+      return {
         template_name: image.template_name,
         image: image.image,
         notebook_name: env.name,
@@ -67,9 +79,23 @@
         master_gpu_count: gpu ? parameters.master_GPU_count : null,
         slave_gpu_count: gpu ? parameters.slave_GPU_count : null,
         gpu_enabled: gpu
-      }, provider);
+      };
+    } else if (provider === 'azure' && image.template_name === 'HDInsight cluster') {
+      return {
+        template_name: image.template_name,
+        image: image.image,
+        name: parameters.cluster_alias_name,
+        project: env.project,
+        custom_tag: parameters.custom_tag,
+        notebook_name: env.name,
+        config: config,
+        hdinsight_master_instance_type: parameters.shape_master,
+        hdinsight_slave_instance_type: parameters.shape_slave,
+        hdinsight_version: parameters.version,
+        hdinsight_instance_count: parameters.instance_number ,
+      };
     } else {
-      return this.userResourceService.createComputationalResource_Dataengine({
+      return {
         name: parameters.cluster_alias_name,
         dataengine_instance_count: parameters.instance_number,
         master_instance_shape: parameters.shape_master,
@@ -85,7 +111,7 @@
         config: config,
         project: env.project,
         custom_tag: parameters.custom_tag
-      }, provider);
+      };
     }
   }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational.resource.model.ts b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational.resource.model.ts
new file mode 100644
index 0000000..d67a29e
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational.resource.model.ts
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export interface ComputationalResourceModel {
+  project_computations: string[];
+  templates: ComputationalTemplate[];
+  user_computations: string[];
+}
+
+export interface ComputationalTemplate {
+  image: string;
+  description: string;
+  templates: TemplatesVersion[];
+  computationGPU: string[];
+  image_type: string;
+  template_name: string;
+  environment_type: string;
+  request_id: string;
+  computation_resources_shapes: ComputationResourcesShapes;
+  limits: {[key: string]: number };
+}
+
+export interface ComputationResourcesShapes {
+  ['GPU optimized']: Shape[];
+  ['Compute optimized']: Shape[];
+  ['Memory optimized']: Shape[];
+  ['For testing']: Shape[];
+}
+
+export interface Shape {
+  Type: string;
+  Size: string;
+  Description: string;
+  Ram: string;
+  Cpu: number;
+  Spot: boolean;
+  SpotPctPrice: number;
+}
+
+export interface TemplatesVersion {
+  applications: Application[];
+  version: string;
+}
+
+export interface Application {
+  Version: string;
+  Name: string;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/index.ts b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/index.ts
index 4586b9e..5776dba 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/index.ts
@@ -25,7 +25,7 @@
 import { FormControlsModule } from '../../../shared/form-controls';
 import { ComputationalResourceCreateDialogComponent } from './computational-resource-create-dialog.component';
 import { ComputationalResourceModel } from './computational-resource-create.model';
-import { KeysPipeModule, UnderscorelessPipeModule } from '../../../core/pipes';
+import { IsElementAvailablePipeModule, KeysPipeModule, UnderscorelessPipeModule } from '../../../core/pipes';
 
 @NgModule({
   imports: [
@@ -35,7 +35,8 @@
     FormControlsModule,
     KeysPipeModule,
     UnderscorelessPipeModule,
-    MaterialModule
+    MaterialModule,
+    IsElementAvailablePipeModule
   ],
   declarations: [ComputationalResourceCreateDialogComponent],
   providers: [ComputationalResourceModel],
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platform-dialog/connected-platform-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platform-dialog/connected-platform-dialog.component.html
new file mode 100644
index 0000000..9540c72
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platform-dialog/connected-platform-dialog.component.html
@@ -0,0 +1,80 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+  <div id="dialog-box" class="dialog__wrapper">
+    <header class="dialog-header">
+      <h4 class="modal-title">
+        {{modalTitle.addPlatform}}
+      </h4>
+      <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+    </header>
+    <div class="dialog-content">
+      <form [formGroup]="connectedPlatformForm">
+          <div class="control__wrapper">
+            <label>Select platform</label>
+            <mat-form-field class="select__wrapper" appearance="fill">
+              <mat-select placeholder="Select platform" name="platformType" formControlName="type">
+                <mat-option *ngIf="!data.types.length" disabled="true">
+                  No platforms to add
+                </mat-option><mat-option *ngFor="let type of data.types" [value]="type">
+                  {{type}}
+                </mat-option>
+              </mat-select>
+              <button class="caret">
+                <i class="material-icons">keyboard_arrow_down</i>
+              </button>
+            </mat-form-field>
+          </div>
+
+        <div class="control__wrapper">
+          <label>Platform url</label>
+          <div class="input__wrapper">
+            <input placeholder="Platform url" type="text" formControlName="url">
+            <span
+              class="error"
+              *ngIf="!connectedPlatformForm?.controls.url.valid
+                        && connectedPlatformForm.controls.url.touched"
+            >
+              Please provide a valid platform url.
+            </span>
+          </div>
+        </div>
+
+        <div class="control__wrapper">
+          <label>Name</label>
+          <div class="input__wrapper">
+            <input placeholder="Enter name" type="text" formControlName="name">
+            <span
+              class="error"
+              *ngIf="!connectedPlatformForm?.controls.name.valid && connectedPlatformForm.controls.name.touched"
+            >
+              Platform name cannot be longer than 6 characters.
+            </span>
+          </div>
+        </div>
+        <div class="button__wrapper">
+          <datalab-modal-btn
+            [isConfirmBtnDisabled]="!isFormValid"
+            [confirmBtnName]="confirmButtonName.add"
+            (closeEvent)="onBtnClick($event)"
+          ></datalab-modal-btn>
+        </div>
+      </form>
+    </div>
+  </div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platform-dialog/connected-platform-dialog.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platform-dialog/connected-platform-dialog.component.scss
new file mode 100644
index 0000000..0becd0d
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platform-dialog/connected-platform-dialog.component.scss
@@ -0,0 +1,98 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+.dialog-content {
+  padding: 25px 30px;
+}
+
+.control__wrapper {
+  display: flex;
+  justify-content: space-between;
+  align-items: baseline;
+  height: 56px;
+}
+
+.select__wrapper {
+  position: relative;
+  width: 320px;
+  height: 36px;
+
+  & ::ng-deep .mat-form-field-wrapper {
+    padding: 0;
+  }
+
+  &.mat-form-field .mat-form-field-flex {
+    background-color: red !important;
+  }
+
+  & ::ng-deep .mat-form-field-appearance-fill .mat-form-field-flex {
+    padding: 0;
+  }
+
+  & ::ng-deep .mat-form-field-infix {
+    border-top: none;
+  }
+
+  & ::ng-deep .mat-form-field-underline::before {
+    height: 0;
+  }
+
+  & ::ng-deep .mat-form-field-ripple {
+    display: none;
+  }
+
+  & ::ng-deep .mat-select-arrow {
+    border: none;
+
+  }
+
+  ::ng-deep .mat-select-placeholder {
+    font-size: 15px;
+  }
+}
+
+.caret {
+  position: absolute;
+  top: -9px;
+  right: -11px;
+  width: 40px;
+  height: 40px;
+  color: #35afd5;
+  background-color: transparent;
+  border: none;
+  border-left: 1px solid #ececec;
+  outline: none;
+  cursor: pointer;
+}
+
+::ng-deep {
+  .mat-form-field .mat-form-field-flex{
+    background-color: white;
+    box-shadow: 0px 3px 1px -2px rgb(0 0 0 / 20%), 0px 2px 2px 0px rgb(0 0 0 / 14%), 0px 1px 5px 0px rgb(0 0 0 / 12%);
+  }
+}
+
+.input__wrapper {
+  width: 320px;
+  height: 56px;
+}
+
+.button__wrapper {
+  padding-top: 20px;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platform-dialog/connected-platform-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platform-dialog/connected-platform-dialog.component.ts
new file mode 100644
index 0000000..6d2f96f
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platform-dialog/connected-platform-dialog.component.ts
@@ -0,0 +1,70 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Component, Inject, OnInit } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { ModalTitle } from '../../images';
+import { AddModalData, AddPlatformFromValue } from '../connected-platforms.models';
+import { ConfirmButtonNames } from '../connected-platforms.config';
+import { PATTERNS } from '../../../core/util';
+
+const URL_REGEXP_VALIDATION_STRING = '^(http(s)?)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]';
+
+@Component({
+  selector: 'datalab-connected-platform-dialog',
+  templateUrl: './connected-platform-dialog.component.html',
+  styleUrls: ['./connected-platform-dialog.component.scss']
+})
+export class ConnectedPlatformDialogComponent implements OnInit {
+  readonly modalTitle: typeof ModalTitle = ModalTitle;
+  readonly confirmButtonName: typeof ConfirmButtonNames = ConfirmButtonNames;
+
+  connectedPlatformForm!: FormGroup;
+
+  constructor(
+    public dialogRef: MatDialogRef<ConnectedPlatformDialogComponent>,
+    private fb: FormBuilder,
+    @Inject(MAT_DIALOG_DATA) public data: AddModalData
+  ) { }
+
+  ngOnInit(): void {
+    this.initForm();
+  }
+
+  onBtnClick(flag: boolean): void {
+    let responseObj: AddPlatformFromValue;
+    if (flag) {
+      responseObj = this.connectedPlatformForm.value;
+    }
+    this.dialogRef.close(responseObj);
+  }
+
+  private initForm(): void {
+    this.connectedPlatformForm = this.fb.group({
+      type: ['', Validators.required],
+      url: ['', [ Validators.required, Validators.pattern(URL_REGEXP_VALIDATION_STRING)]],
+      name: ['', [ Validators.required, Validators.pattern(PATTERNS.projectName), Validators.minLength(2)]]
+    });
+  }
+
+  get isFormValid(): boolean {
+    return this.connectedPlatformForm.valid;
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms-routing.module.ts b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms-routing.module.ts
new file mode 100644
index 0000000..61d9380
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms-routing.module.ts
@@ -0,0 +1,35 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { ConnectedPlatformsComponent } from './connected-platforms.component';
+
+const routes: Routes = [
+  {
+    path: '',
+    component: ConnectedPlatformsComponent
+  }
+];
+
+@NgModule({
+  imports: [RouterModule.forChild(routes)],
+  exports: [RouterModule]
+})
+export class ConnectedPlatformsRoutingModule { }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.html
new file mode 100644
index 0000000..08acd36
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.html
@@ -0,0 +1,96 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<section class="connected-platforms__wrapper base-retreat">
+  <nav class="sub-nav">
+    <button
+      *ngIf="(connectedPlatformsStatus$ | async)?.add"
+      (click)="onAddNew()"
+      mat-raised-button
+      class="butt butt-create"
+    >
+      <i class="material-icons">add</i>Add new
+    </button>
+  </nav>
+
+  <mat-divider></mat-divider>
+
+  <table mat-table [dataSource]="(platformPageData$ | async).userPlatforms" class="mat-elevation-z8 table">
+
+    <ng-container matColumnDef="platformName">
+      <th mat-header-cell *matHeaderCellDef>{{tableHeaderCellTitles.platformName}}</th>
+      <td mat-cell class="column" *matCellDef="let element"> {{element.name}} </td>
+    </ng-container>
+
+    <ng-container matColumnDef="linkToPlatform">
+      <th mat-header-cell *matHeaderCellDef>{{tableHeaderCellTitles.linkToPlatform}}</th>
+      <td class="column" mat-cell *matCellDef="let element">
+        <a
+          class="link"
+          [href]="element.url | normalizeLink"
+          target="_blank"
+          [matTooltip]="element.url"
+          matTooltipPosition="above"
+          [matTooltipDisabled]="element.url.length < maxUrlLength"
+        >
+          {{element.url | truncateTextPipe : maxUrlLength}}
+        </a>
+      </td>
+    </ng-container>
+
+    <ng-container matColumnDef="actions">
+      <th
+        mat-header-cell
+        [ngClass]="{'hided-table-title': !(connectedPlatformsStatus$ | async)?.disconnect}"
+        *matHeaderCellDef
+      >
+        {{tableHeaderCellTitles.actions}}
+      </th>
+      <td mat-cell class="action-cell" *matCellDef="let element">
+        <span class="actions-menu"
+              #settings
+              (click)="actions.toggle($event, settings)">
+          <img
+            *ngIf="(connectedPlatformsStatus$ | async)?.disconnect"
+            class="action-icon"
+            [src]="'assets/svg/settings_icon.svg'"
+            alt="setting-icon"
+          >
+        </span>
+        <bubble-up #actions class="list-menu" position="bottom-left" alternative="top-left">
+          <ul class="list-unstyled">
+            <li>
+              <button
+                class="action-button__disconnect"
+                (click)="onPlatformDisconnect(element)"
+              >
+                <i class="material-icons icon">cast</i>
+                <span>Disconnect</span>
+              </button>
+            </li>
+          </ul>
+        </bubble-up>
+      </td>
+    </ng-container>
+
+    <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+    <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
+  </table>
+
+</section>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss
new file mode 100644
index 0000000..7dd0435
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.scss
@@ -0,0 +1,99 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+.table {
+  width: 100%;
+}
+
+.column {
+  width: 20%;
+}
+
+.action-icon,
+.link {
+  cursor: pointer;
+}
+
+.link {
+  text-decoration: underline;
+}
+
+.hided-table-title {
+  color: transparent;
+}
+
+.table-cell {
+  position: relative;
+}
+
+.list-menu {
+  left: auto;
+  top: 30px !important;
+  width: 190px;
+  max-height: calc(100vh / 2 - 70px);
+  margin-left: 0;
+  box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12);
+  border: none;
+}
+
+.actions-menu {
+  position: relative;
+  width: 190px;
+}
+
+.action-button__disconnect {
+  display: flex;
+  align-items: center;
+  width: 100%;
+  padding: 10px 15px;
+  background-color: transparent;
+  color: rgb(87, 114, 137);
+  border: none;
+  outline: none;
+
+  &:hover {
+    color: #35afd5;
+    cursor: pointer;
+
+    & ::before {
+      background-color: #35afd5;
+    }
+  }
+}
+
+.action-cell {
+  position: relative;
+}
+
+.icon {
+  position: relative;
+  margin-right: 10px;
+
+  &::before {
+    position: absolute;
+    top: 11px;
+    left: -4px;
+    width: 32px;
+    height: 1px;
+    rotate: 40deg;
+    content: '';
+    background-color: #577289;
+    transform: rotateX(1deg);
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.ts
new file mode 100644
index 0000000..b49dbc5
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.component.ts
@@ -0,0 +1,114 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Component, OnInit } from '@angular/core';
+import { BehaviorSubject, EMPTY, Observable, pipe } from 'rxjs';
+import { switchMap, take, tap } from 'rxjs/operators';
+import { MatDialog } from '@angular/material/dialog';
+import { ToastrService } from 'ngx-toastr';
+
+import { ConnectedPlatformsStatus, GeneralEnvironmentStatus } from '../../administration/management/management.model';
+import { HealthStatusService } from '../../core/services';
+import { ConnectedPlatformsTableTitles, ConnectedPlatformDisplayedColumns } from './connected-platforms.config';
+import { ConnectedPlatformDialogComponent } from './connected-platform-dialog/connected-platform-dialog.component';
+import { ConnectedPlatformsInfo, Platform } from './connected-platforms.models';
+import { ConnectedPlatformsService } from './connected-platforms.service';
+import { WarningDialogComponent } from './warning-dialog/warning-dialog.component';
+
+@Component({
+  selector: 'datalab-connected-platforms',
+  templateUrl: './connected-platforms.component.html',
+  styleUrls: ['./connected-platforms.component.scss']
+})
+export class ConnectedPlatformsComponent implements OnInit {
+  readonly tableHeaderCellTitles: typeof ConnectedPlatformsTableTitles = ConnectedPlatformsTableTitles;
+  readonly maxUrlLength: number = 30;
+
+  // tslint:disable-next-line:max-line-length
+  private readonly connectedPlatformsStatus$$: BehaviorSubject<ConnectedPlatformsStatus> = new BehaviorSubject<ConnectedPlatformsStatus>({} as ConnectedPlatformsStatus);
+  readonly connectedPlatformsStatus$: Observable<ConnectedPlatformsStatus> = this.connectedPlatformsStatus$$.asObservable();
+
+  platformPageData$: Observable<ConnectedPlatformsInfo>;
+
+  displayedColumns: typeof ConnectedPlatformDisplayedColumns = ConnectedPlatformDisplayedColumns;
+
+  constructor(
+    private healthStatusService: HealthStatusService,
+    public toastr: ToastrService,
+    private dialog: MatDialog,
+    private connectedPlatformsService: ConnectedPlatformsService
+  ) { }
+
+  ngOnInit(): void {
+    this.getEnvironmentHealthStatus();
+    this.getConnectedPlatformPageInfo();
+    this.initPageData();
+  }
+
+  onAddNew(): void {
+    this.dialog.open(ConnectedPlatformDialogComponent, {
+      data: this.connectedPlatformsService.addModalData,
+      panelClass: 'modal-lg'
+    })
+      .afterClosed()
+      .pipe(
+        this.getModalAction(this.connectedPlatformsService.addPlatform),
+      ).subscribe();
+  }
+
+  onPlatformDisconnect({name}: Platform): void {
+    this.dialog.open(WarningDialogComponent,
+      {
+        data: name,
+        panelClass: 'modal-sm'
+      })
+      .afterClosed()
+      .pipe(
+        this.getModalAction(this.connectedPlatformsService.disconnectPlatform)
+      ).subscribe();
+  }
+
+  private getModalAction(callback: Function) {
+    callback = callback.bind(this.connectedPlatformsService);
+    return pipe(
+      switchMap((arg) => {
+        if (arg) {
+          return callback(arg);
+        }
+        return EMPTY;
+      }),
+      switchMap(() => this.connectedPlatformsService.getConnectedPlatformPageInfo())
+    );
+  }
+
+  private getEnvironmentHealthStatus(): void {
+    this.healthStatusService.getEnvironmentHealthStatus().pipe(
+      tap((response: GeneralEnvironmentStatus) => this.connectedPlatformsStatus$$.next(response.connectedPlatforms)),
+      take(1)
+    ).subscribe();
+  }
+
+  private getConnectedPlatformPageInfo(): void {
+    this.connectedPlatformsService.getConnectedPlatformPageInfo().subscribe();
+  }
+
+  private initPageData(): void {
+    this.platformPageData$ = this.connectedPlatformsService.platformPageData$;
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.config.ts b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.config.ts
new file mode 100644
index 0000000..708ff52
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.config.ts
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export enum ConnectedPlatformsTableTitles {
+  platformName = 'Platform name',
+  linkToPlatform = 'Link to platform',
+  actions = 'Actions'
+}
+
+export const ConnectedPlatformDisplayedColumns = [
+  'platformName',
+  'linkToPlatform',
+  'actions',
+];
+
+export enum ModalTitles {
+  disconnect= 'Disconnect platform'
+}
+
+export enum ConfirmButtonNames {
+  yes = 'Yes',
+  add = 'Add'
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.models.ts b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.models.ts
new file mode 100644
index 0000000..d514879
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.models.ts
@@ -0,0 +1,35 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export interface ConnectedPlatformsInfo {
+  userPlatforms: Platform[];
+  types: string[];
+  platformNames: string[];
+}
+
+export interface Platform {
+  name: string;
+  type: string;
+  user: string;
+  url: string;
+}
+
+export type AddModalData = Omit<ConnectedPlatformsInfo, 'userPlatforms'>;
+
+export type AddPlatformFromValue = Omit<Platform, 'user'>;
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.module.ts b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.module.ts
new file mode 100644
index 0000000..6d230e8
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.module.ts
@@ -0,0 +1,53 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+
+import { ConnectedPlatformsRoutingModule } from './connected-platforms-routing.module';
+import { ConnectedPlatformsComponent } from './connected-platforms.component';
+import { MaterialModule } from '../../shared/material.module';
+import { NormalizeLinkPipeModule } from '../../core/pipes';
+import { BubbleModule } from '../../shared';
+import { ReactiveFormsModule } from '@angular/forms';
+import { TruncateTextPipeModule } from '../../core/pipes/truncate-text-pipe';
+import { ModalPartsModule } from '../../shared/modal-parts/modal-parts.module';
+import { WarningDialogComponent } from './warning-dialog/warning-dialog.component';
+import { ConnectedPlatformDialogComponent } from './connected-platform-dialog/connected-platform-dialog.component';
+
+
+@NgModule({
+  declarations: [
+    ConnectedPlatformsComponent,
+    WarningDialogComponent,
+    ConnectedPlatformDialogComponent
+  ],
+  imports: [
+    CommonModule,
+    MaterialModule,
+    NormalizeLinkPipeModule,
+    ConnectedPlatformsRoutingModule,
+    BubbleModule,
+    ModalPartsModule,
+    ReactiveFormsModule,
+    TruncateTextPipeModule
+  ],
+  entryComponents: [ ConnectedPlatformDialogComponent, WarningDialogComponent ]
+})
+export class ConnectedPlatformsModule { }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.service.ts b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.service.ts
new file mode 100644
index 0000000..3a98616
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/connected-platforms.service.ts
@@ -0,0 +1,59 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Injectable } from '@angular/core';
+import { ConnectedPlatformApiService } from '../../core/services/connected-platform-api.service';
+import { tap } from 'rxjs/operators';
+import { BehaviorSubject, Observable } from 'rxjs';
+import { AddModalData, AddPlatformFromValue, ConnectedPlatformsInfo } from './connected-platforms.models';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class ConnectedPlatformsService {
+  // tslint:disable-next-line:max-line-length
+  private platformPageData$$: BehaviorSubject<ConnectedPlatformsInfo> = new BehaviorSubject<ConnectedPlatformsInfo>({} as ConnectedPlatformsInfo);
+  platformPageData$: Observable<ConnectedPlatformsInfo> = this.platformPageData$$.asObservable();
+  addModalData: AddModalData;
+
+  constructor(
+    private connectedPlatformPageService: ConnectedPlatformApiService
+  ) { }
+
+  getConnectedPlatformPageInfo(): Observable<ConnectedPlatformsInfo> {
+    return this.connectedPlatformPageService.getConnectedPlatformsPage()
+      .pipe(
+        tap( result => this.platformPageData$$.next(result)),
+        tap( result => this.getAddModalData(result)),
+      );
+  }
+
+  addPlatform(platformParams: AddPlatformFromValue): Observable<any> {
+    return this.connectedPlatformPageService.addPlatform(platformParams);
+  }
+
+  disconnectPlatform(platformName: string): Observable<any> {
+    return this.connectedPlatformPageService.disconnectPlatform(platformName);
+  }
+
+  private getAddModalData(info: ConnectedPlatformsInfo): void {
+    const { platformNames, types } = info;
+    this.addModalData = { platformNames, types };
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/warning-dialog/warning-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/warning-dialog/warning-dialog.component.html
new file mode 100644
index 0000000..32d382c
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/warning-dialog/warning-dialog.component.html
@@ -0,0 +1,28 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<datalab-modal-header (close)="onClose()" [modalTitle]="title.disconnect"></datalab-modal-header>
+<div class="dialog-content">
+  <p class="content red">The <span class="platform-name">{{data}}</span> will be disconnected from this account.</p>
+  <datalab-modal-btn
+    [needAdditionalQuestion]="true"
+    (closeEvent)="onBtnClick($event)"
+    [confirmBtnName]="confirmButtonName.yes"
+  ></datalab-modal-btn>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/warning-dialog/warning-dialog.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/warning-dialog/warning-dialog.component.scss
new file mode 100644
index 0000000..310d4b0
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/warning-dialog/warning-dialog.component.scss
@@ -0,0 +1,37 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+.dialog-content {
+  padding: 25px 30px;
+}
+
+.red {
+  color: red;
+}
+
+.content {
+  margin-bottom: 50px;
+  padding-top: 20px;
+  text-align: center;
+  font-weight: 400;
+}
+
+.platform-name {
+  font-weight: 700;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/warning-dialog/warning-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/warning-dialog/warning-dialog.component.ts
new file mode 100644
index 0000000..f30f0d3
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/connected-platforms/warning-dialog/warning-dialog.component.ts
@@ -0,0 +1,49 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Component, Inject } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { ConfirmButtonNames, ModalTitles } from '../connected-platforms.config';
+
+@Component({
+  selector: 'datalab-warning-dialog',
+  templateUrl: './warning-dialog.component.html',
+  styleUrls: ['./warning-dialog.component.scss']
+})
+export class WarningDialogComponent {
+  readonly title: typeof ModalTitles = ModalTitles;
+  readonly confirmButtonName: typeof ConfirmButtonNames = ConfirmButtonNames;
+
+  constructor(
+    public dialogRef: MatDialogRef<WarningDialogComponent>,
+    @Inject(MAT_DIALOG_DATA) public data: string
+  ) { }
+
+  onClose(): void {
+    this.dialogRef.close();
+  }
+
+  onBtnClick(isConfirm: boolean): void {
+    let platformName;
+    if (isConfirm) {
+      platformName = this.data;
+    }
+    this.dialogRef.close(platformName);
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html
index ae576f2..a5befe2 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html
@@ -45,19 +45,19 @@
         </div>
       </form>
       <div class="text-center m-top-30 m-bott-10">
-        <button 
-          mat-raised-button 
-          type="button" 
-          class="butt action" 
+        <button
+          mat-raised-button
+          type="button"
+          class="butt action"
           (click)="dialogRef.close()"
         >
           Cancel
         </button>
-        <button 
-          mat-raised-button 
-          type="button" 
+        <button
+          mat-raised-button
+          type="button"
           [disabled]="!createAMIForm.valid"
-          (click)="assignChanges(createAMIForm.value)" 
+          (click)="assignChanges(createAMIForm.value)"
           class="butt butt-success action"
         >
           Create
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts
index 315f8f3..455468a 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts
@@ -22,7 +22,7 @@
 import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
 import { ToastrService } from 'ngx-toastr';
 
-import { UserResourceService } from '../../../core/services';
+import {ManageEnvironmentsService, UserResourceService} from '../../../core/services';
 import { HTTP_STATUS_CODES, PATTERNS } from '../../../core/util';
 import { DICTIONARY } from '../../../../dictionary/global.dictionary';
 
@@ -38,6 +38,7 @@
   public provider: string;
   delimitersRegex = /[-_]?/g;
   imagesList: any;
+  private isAdmin: boolean = false;
 
   constructor(
     @Inject(MAT_DIALOG_DATA) public data: any,
@@ -45,28 +46,43 @@
     public dialogRef: MatDialogRef<AmiCreateDialogComponent>,
     private _userResource: UserResourceService,
     private _fb: FormBuilder,
+    private manageEnvironmentsService: ManageEnvironmentsService,
   ) { }
 
   ngOnInit() {
     this.notebook = this.data;
     this.provider = this.data.cloud_provider;
+    this.checkRole();
 
     this.initFormModel();
     this._userResource.getImagesList(this.data.project).subscribe(res => this.imagesList = res);
   }
 
-  public assignChanges(data) {
-    this._userResource.createAMI(data).subscribe(
-      response => response.status === HTTP_STATUS_CODES.ACCEPTED && this.dialogRef.close(true),
-      error => this.toastr.error(error.message || `Image creation failed!`, 'Oops!'));
+  public assignChanges(data): void {
+    if (this.isAdmin) {
+      const { exploratory_name, project_name, name, description } = data;
+      const imageInfo = { user: this.data.userName,   imageName: name,   description, project_name, exploratory_name};
+      this.manageEnvironmentsService.environmentManagement(imageInfo, 'createImage', project_name, exploratory_name).subscribe(
+        () => { this.dialogRef.close(true); });
+    } else {
+      this._userResource.createAMI(data).subscribe(
+        response => response.status === HTTP_STATUS_CODES.ACCEPTED && this.dialogRef.close(true),
+        error => this.toastr.error(error.message || `Image creation failed!`, 'Oops!'));
+    }
+  }
+
+  private checkRole(): void {
+    if (this.data?.isAdmin) {
+      this.isAdmin = this.data.isAdmin;
+    }
   }
 
   private initFormModel(): void {
     this.createAMIForm = this._fb.group({
       name: ['', [
-        Validators.required, 
-        Validators.pattern(PATTERNS.namePattern), 
-        Validators.maxLength(10), 
+        Validators.required,
+        Validators.pattern(PATTERNS.namePattern),
+        Validators.maxLength(10),
         this.checkDuplication.bind(this)
       ]],
       description: [''],
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.html
index db3615d..6f133a0 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.html
@@ -29,10 +29,10 @@
           <label class="label">Select project</label>
           <div class="control selector-wrapper">
             <mat-form-field>
-              <mat-select 
-                formControlName="project" 
-                disableOptionCentering 
-                panelClass="create-resources-dialog scrolling" 
+              <mat-select
+                formControlName="project"
+                disableOptionCentering
+                panelClass="create-resources-dialog scrolling"
                 placeholder="Select project"
               >
                 <mat-option *ngFor="let project of projects" [value]="project.name" (click)="setEndpoints(project)">
@@ -53,15 +53,15 @@
           <label class="label">Select endpoint</label>
           <div class="control selector-wrapper" [ngClass]="{ 'not-active' : !endpoints.length }">
             <mat-form-field>
-              <mat-select 
-                formControlName="endpoint" 
-                disableOptionCentering 
+              <mat-select
+                formControlName="endpoint"
+                disableOptionCentering
                 [disabled]="!endpoints.length"
-                panelClass="create-resources-dialog scrolling" 
+                panelClass="create-resources-dialog scrolling"
                 placeholder="Select endpoint"
               >
-                <mat-option 
-                  *ngFor="let endpoint of endpoints" 
+                <mat-option
+                  *ngFor="let endpoint of endpoints"
                   [value]="endpoint"
                   (click)="getTemplates(createExploratoryForm?.controls['project'].value, endpoint)"
                 >
@@ -80,7 +80,7 @@
 
         <div class="control-group">
           <label class="label">Select template</label>
-          <div 
+          <div
             class="control selector-wrapper"
             [matTooltip]="'Notebook creations are not available. Please, check your permissions.'"
             matTooltipPosition="above"
@@ -89,16 +89,16 @@
           >
             <span class="form-field-wrapper"  [ngClass]="{ 'not-active' : !templates.length  || (templates.length === 0 && this.createExploratoryForm.controls.endpoint.value)}">
               <mat-form-field>
-                <mat-select 
-                  formControlName="version" 
-                  disableOptionCentering 
+                <mat-select
+                  formControlName="version"
+                  disableOptionCentering
                   [disabled]="!templates.length || (templates.length === 0 && this.createExploratoryForm.controls.endpoint.value)"
-                  panelClass="create-resources-dialog scrolling" 
+                  panelClass="create-resources-dialog scrolling"
                   placeholder="Select template"
                 >
-                  <mat-option 
+                  <mat-option
                     *ngFor="let template of templates"
-                    [value]="template.exploratory_environment_versions[0].version" 
+                    [value]="template.exploratory_environment_versions[0].version"
                     (click)="getShapes(template)"
                   >
                     {{ template.exploratory_environment_versions[0].template_name }}
@@ -115,8 +115,8 @@
           </div>
         </div>
 
-        <div 
-          class="image-description control-group" 
+        <div
+          class="image-description control-group"
           *ngIf="selectedCloud !== 'gcp' && currentTemplate?.image === 'docker.datalab-deeplearning'"
         >
           <label class="label"></label>
@@ -126,22 +126,22 @@
           </div>
         </div>
 
-        <div class="control-group" *ngIf="images && images.length > 0">
+        <div class="control-group" *ngIf="images?.length">
           <label class="label">Select image</label>
           <div class="control selector-wrapper">
             <mat-form-field>
               <mat-label>Select image</mat-label>
               <mat-select formControlName="notebook_image_name" panelClass="create-resources-dialog scrolling" disableOptionCentering>
-                <mat-option 
-                  *ngIf="currentTemplate?.image !== 'docker.datalab-deeplearning'" 
-                  [value]="null" 
+                <mat-option
+                  *ngIf="currentTemplate?.image !== 'docker.datalab-deeplearning'"
+                  [value]="null"
                   (click)="setImage(null)"
                 >
                   None
                 </mat-option>
-                <mat-option 
-                  *ngFor="let image of images" 
-                  [value]="image?.name" 
+                <mat-option
+                  *ngFor="let image of images"
+                  [value]="image?.name"
                   (click)="setImage(image)"
                 >
                   {{ image?.status ? image?.name + ' (custom image)' : image?.name }}
@@ -157,8 +157,8 @@
           </div>
         </div>
 
-        <div 
-          class="image-description control-group" 
+        <div
+          class="image-description control-group"
           *ngIf="selectedImage?.description"
         >
           <label class="label"></label>
@@ -171,19 +171,19 @@
         <div class="control-group name-control">
           <label class="label">Name</label>
           <div class="control">
-            <input 
+            <input
               [class.danger_field]=" !createExploratoryForm?.controls['name'].valid
                 && createExploratoryForm?.controls['name'].dirty
-                && createExploratoryForm?.controls['name'].hasError('duplication')" 
+                && createExploratoryForm?.controls['name'].hasError('duplication')"
               type="text"
-              class="form-control" 
-              placeholder="Enter Name" 
+              class="form-control"
+              placeholder="Enter Name"
               formControlName="name"
             />
             <span class="error" *ngIf="createExploratoryForm?.controls['name'].hasError('duplication')">This name already exists in current project.</span>
-            <span 
-              class="error" 
-              *ngIf="createExploratoryForm?.controls['name'].hasError('maxlength') 
+            <span
+              class="error"
+              *ngIf="createExploratoryForm?.controls['name'].hasError('maxlength')
                 && !createExploratoryForm?.controls['name'].hasError('pattern')"
             >
               Name cannot be longer than {{maxNotebookLength}} characters.
@@ -196,7 +196,7 @@
 
         <div class="control-group">
           <label class="label">Instance size</label>
-          <div 
+          <div
             class="control selector-wrapper"
             [matTooltip]="'Instance size are not available. Please, check your permissions.'"
             matTooltipPosition="above"
@@ -206,11 +206,11 @@
             <span class="form-field-wrapper" [ngClass]="{ 'not-active': !currentTemplate || !areShapes && currentTemplate}">
               <mat-form-field>
                 <mat-label>Select instance size</mat-label>
-                <mat-select 
-                  formControlName="shape" 
-                  disableOptionCentering 
+                <mat-select
+                  formControlName="shape"
+                  disableOptionCentering
                   [disabled]="!currentTemplate || !areShapes && currentTemplate"
-                  panelClass="create-resources-shapes scrolling" 
+                  panelClass="create-resources-shapes scrolling"
                   placeholder="Instance size"
                 >
                   <mat-optgroup *ngFor="let item of (shapes | keys)" [label]="item.key | underscoreless">
@@ -227,7 +227,7 @@
           </div>
         </div>
 
-        <div 
+        <div
           class="control-group m-bott-10"
           [ngClass]="{'m-bott-20': createExploratoryForm?.controls['custom_tag'].hasError('pattern')}"
         >
@@ -235,14 +235,14 @@
           <div class="control">
             <input type="text" class="form-control" placeholder="Enter custom tag" formControlName="custom_tag">
           </div>
-          <span 
+          <span
             class="error"
             *ngIf="createExploratoryForm?.controls['custom_tag'].hasError('maxlength') &&
                   !createExploratoryForm?.controls['custom_tag'].hasError('pattern')"
           >
             Custom tag name cannot be longer than {{maxCustomTagLength}} characters.
           </span>
-          <span 
+          <span
             class="error"
             *ngIf="createExploratoryForm?.controls['custom_tag'].hasError('pattern')"
           >
@@ -250,15 +250,15 @@
         </div>
 
         <div *ngIf="currentTemplate">
-          <ng-template 
-            [ngIf]="selectedCloud === 'gcp' 
-              && (currentTemplate?.image === 'docker.datalab-jupyter' 
+          <ng-template
+            [ngIf]="selectedCloud === 'gcp'
+              && (currentTemplate?.image === 'docker.datalab-jupyter'
               || currentTemplate?.image === 'docker.datalab-deeplearning'
               || currentTemplate?.image === 'docker.datalab-tensor')"
           >
             <div class="checkbox-group">
-              <div 
-                class="d-flex cursor-pointer label m-bott-20" 
+              <div
+                class="d-flex cursor-pointer label m-bott-20"
                 *ngIf="currentTemplate?.image === 'docker.datalab-jupyter'"
                 (click)="addGpuFields()"
               >
@@ -267,14 +267,15 @@
                 </div>
                 <span class=" pl-5">GPU</span>
               </div>
-              <ng-template 
-                [ngIf]="this.additionalParams.gpu || 
+              <ng-template
+                [ngIf]="this.additionalParams.gpu ||
                   currentTemplate?.image === 'docker.datalab-deeplearning' ||
                   currentTemplate?.image === 'docker.datalab-tensor'"
               >
+                <!---<div *ngIf="currentTemplate?.image !== 'docker.datalab-jupyter-gpu'" class="control-group"> --->
                 <div class="control-group">
                   <label class="label">GPU type</label>
-                  <div 
+                  <div
                     class="control selector-wrapper"
                     [matTooltip]="'Please, select instance size.'"
                     matTooltipPosition="above"
@@ -284,11 +285,11 @@
                     <span class="form-field-wrapper" [ngClass]="{ 'not-active': !createExploratoryForm.controls['shape'].value}">
                       <mat-form-field>
                         <mat-label>Select GPU type</mat-label>
-                        <mat-select 
-                          formControlName="gpu_type" 
-                          disableOptionCentering 
+                        <mat-select
+                          formControlName="gpu_type"
+                          disableOptionCentering
                           [disabled]="!createExploratoryForm.controls['shape'].value"
-                          panelClass="create-resources-dialog" 
+                          panelClass="create-resources-dialog"
                           placeholder="GPU type"
                         >
                           <mat-option *ngFor="let list_item of gpuTypes; index as i" [value]="list_item" (click)="setCount('', list_item)">
@@ -307,7 +308,7 @@
                 </div>
                 <div class="control-group">
                   <label class="label">GPU count</label>
-                  <div 
+                  <div
                     class="control selector-wrapper"
                     [matTooltip]="'Please, select GPU type.'"
                     matTooltipPosition="above"
@@ -317,9 +318,9 @@
                     <span class="form-field-wrapper" [ngClass]="{ 'not-active': !createExploratoryForm.controls['gpu_type'].value}">
                       <mat-form-field>
                         <mat-label>Select GPU count</mat-label>
-                        <mat-select 
-                          formControlName="gpu_count" 
-                          disableOptionCentering 
+                        <mat-select
+                          formControlName="gpu_count"
+                          disableOptionCentering
                           [disabled]="!createExploratoryForm.controls['gpu_type'].value"
                           panelClass="create-resources-dialog"
                           placeholder="GPU count"
@@ -338,10 +339,10 @@
               </ng-template>
             </div>
           </ng-template>
-          <div 
+          <div
             class="checkbox-group"
-            *ngIf="currentTemplate?.image !== 'docker.datalab-zeppelin' 
-              && currentTemplate?.image !== 'docker.datalab-superset' 
+            *ngIf="currentTemplate?.image !== 'docker.datalab-zeppelin'
+              && currentTemplate?.image !== 'docker.datalab-superset'
               && currentTemplate?.image !== 'docker.datalab-jupyterlab'"
           >
             <div class="d-flex cursor-pointer label m-bott-20" (click)="selectConfiguration()">
@@ -351,15 +352,15 @@
               <span class=" pl-5">Spark configurations</span>
             </div>
             <div class="config-details" [ngClass]="{ show: this.additionalParams.configurationNode}">
-              <textarea 
-                formControlName="cluster_config" 
+              <textarea
+                formControlName="cluster_config"
                 placeholder="Cluster configuration template, JSON"
-                data-gramm_editor="false" 
+                data-gramm_editor="false"
                 id="config"
               ></textarea>
-              <span 
+              <span
                 class="error spark-config"
-                *ngIf="!createExploratoryForm?.controls.cluster_config.valid 
+                *ngIf="!createExploratoryForm?.controls.cluster_config.valid
                   && createExploratoryForm?.controls['cluster_config'].dirty"
               >
                 Configuration parameters is not in a valid format.
@@ -376,17 +377,17 @@
         </div>
 
         <div class="text-center m-top-30"  id="buttons">
-          <button 
-            mat-raised-button 
-            type="button" 
-            class="butt action" 
+          <button
+            mat-raised-button
+            type="button"
+            class="butt action"
             (click)="dialogRef.close()"
           >
             Cancel
           </button>
-          <button 
-            mat-raised-button 
-            type="button" 
+          <button
+            mat-raised-button
+            type="button"
             class="butt butt-success action"
             [disabled]="!createExploratoryForm?.valid"
             (click)="createExploratoryEnvironment(createExploratoryForm.value)"
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.ts
index a5bb5e1..f75853e 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.ts
@@ -22,13 +22,14 @@
 import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
 import { ToastrService } from 'ngx-toastr';
 
-import { Project } from '../../../administration/project/project.component';
 import { UserResourceService, ProjectService } from '../../../core/services';
 import { CheckUtils, SortUtils, HTTP_STATUS_CODES, PATTERNS, HelpUtils } from '../../../core/util';
 import { DICTIONARY } from '../../../../dictionary/global.dictionary';
 import { CLUSTER_CONFIGURATION } from '../../computational/computational-resource-create-dialog/cluster-configuration-templates';
 import { tap } from 'rxjs/operators';
 import { timer } from 'rxjs';
+import { DockerImageName } from '../../../core/models';
+import { Project } from '../../../administration/project/project.model';
 
 @Component({
   selector: 'create-environment',
@@ -51,6 +52,7 @@
   selectedImage: any;
   maxNotebookLength: number = 14;
   maxCustomTagLength: number = 63;
+  templateName = DockerImageName;
   public areShapes: boolean;
   public selectedCloud: string = '';
   public gpuCount: Array<number>;
@@ -109,7 +111,7 @@
   public setEndpoints(project) {
     const controls = ['endpoint', 'version', 'shape', 'gpu_type', 'gpu_count'];
     this.resetSelections(controls);
-    
+
     this.endpoints = project.endpoints
       .filter(e => e.status === 'RUNNING')
       .map(e => e.name);
@@ -171,15 +173,16 @@
       this.createExploratoryForm.controls['notebook_image_name'].setValidators([Validators.required]);
       this.createExploratoryForm.controls['notebook_image_name'].updateValueAndValidity();
     }
-    
-    if (this.selectedCloud === 'gcp' && 
+
+    if (this.selectedCloud === 'gcp' &&
         (template?.image === 'docker.datalab-jupyter' ||
         template?.image === 'docker.datalab-deeplearning' ||
         template?.image === 'docker.datalab-tensor')) {
-          
+
       this.gpuTypes = template?.computationGPU ? HelpUtils.sortGpuTypes(template.computationGPU) : [];
 
-      if(template?.image === 'docker.datalab-tensor' || template?.image === 'docker.datalab-deeplearning') {
+      // tslint:disable-next-line:max-line-length
+      if (template?.image === 'docker.datalab-tensor' /**|| template?.image === 'docker.datalab-jupyter-conda'|| template?.image === 'docker.datalab-jupyter-gpu' */|| template?.image === 'docker.datalab-deeplearning') {
         this.addGpuFields();
       }
     }
@@ -215,8 +218,8 @@
       template_name: this.currentTemplate.exploratory_environment_versions[0].template_name
     };
 
-    if (!data.notebook_image_name 
-      && this.currentTemplate.image === 'docker.datalab-deeplearning' 
+    if (!data.notebook_image_name
+      && this.currentTemplate.image === 'docker.datalab-deeplearning'
       && (this.selectedCloud === 'aws' || this.selectedCloud === 'azure')) {
       data.notebook_image_name = this.currentTemplate.exploratory_environment_versions[0].version;
     }
@@ -259,7 +262,7 @@
       });
 
     } else {
-      controls.forEach(control => {
+        controls.forEach(control => {
         this.createExploratoryForm.controls[control].setValidators([Validators.required]);
         this.createExploratoryForm.controls[control].updateValueAndValidity();
       });
@@ -270,10 +273,15 @@
   }
 
   public setInstanceSize() {
-    const controls = ['gpu_type', 'gpu_count'];
-    controls.forEach(control => {
-      this.createExploratoryForm.controls[control].setValue(null);
-    });
+    const {image, computationGPU} = this.currentTemplate;
+    if (image === this.templateName.jupyterJpu) {
+      this.createExploratoryForm.get('gpu_count').setValue(computationGPU[0]);
+    } else {
+        const controls = ['gpu_type', 'gpu_count'];
+        controls.forEach(control => {
+        this.createExploratoryForm.controls[control].setValue(null);
+      });
+    }
   }
 
   public setCount(type: any, gpuType: any): void {
@@ -320,11 +328,11 @@
       this.createExploratoryForm.controls['endpoint'].value)
       .subscribe(
         (res: any) => {
-          this.images = res.filter(el => el.status === 'CREATED');
-          
-          if(this.selectedCloud === 'gcp' && this.currentTemplate.image === 'docker.datalab-deeplearning') {
+          this.images = res.filter(el => el.status === 'ACTIVE');
+
+          if (this.selectedCloud === 'gcp' && this.currentTemplate.image === 'docker.datalab-deeplearning') {
             this.currentTemplate.exploratory_environment_images = this.currentTemplate.exploratory_environment_images.map(image => {
-              return {name: image['Image family'] ?? image.name, description: image['Description'] ?? image.description}
+              return {name: image['Image family'] ?? image.name, description: image['Description'] ?? image.description};
             });
             this.images.push(...this.currentTemplate.exploratory_environment_images);
           }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.html
index bcced52..80c11d6 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.html
@@ -68,15 +68,15 @@
           <!--              </a>-->
           <!--            </p> -->
             <ng-container *ngFor="let item of notebook.exploratory_urls">
-              <span 
-                class="d-none" 
-                *ngIf="item.description.toLowerCase() === 'ungit' 
+              <span
+                class="d-none"
+                *ngIf="item.description.toLowerCase() === 'ungit'
                   && notebook.exploratory_urls[0].description.toLowerCase().indexOf('zeppelin') !== -1; else ungit"
               ></span>
               <ng-template #ungit>
                 <p (mouseleave)="hideCopyIcon()">
                   <span class="description">{{item.description}}: &nbsp;</span>
-                  <a 
+                  <a
                     (mouseover)="showCopyIcon(item.description)"
                     (click)="logAction(notebook.name, item.description)"
                     class="ellipsis none-select resources-url" matTooltip="{{item.url}}"
@@ -85,13 +85,13 @@
                     target="_blank"
                     (contextmenu)="false"
                   >
-                    &nbsp;{{item.url}}
+                    &nbsp;{{item.url | truncateTextPipe: urlMaxLength}}
                   </a>
-                  <span 
-                    (click)="logAction(notebook.name, item.description, 'Copy');$event.stopPropagation()" 
-                    *ngIf="isCopyIconVissible[item.description]" 
-                    [matTooltip]="isCopied ? 'Copy ' + item.description + ' url': 'Copied'" 
-                    matTooltipPosition="above" 
+                  <span
+                    (click)="logAction(notebook.name, item.description, 'Copy');$event.stopPropagation()"
+                    *ngIf="isCopyIconVissible[item.description]"
+                    [matTooltip]="isCopied ? 'Copy ' + item.description + ' url': 'Copied'"
+                    matTooltipPosition="above"
                     class="copy-icon-wrapper"
                   >
                     <span  class="link-icon" (click)="copyLink(item.url)" >
@@ -105,22 +105,22 @@
         </div>
         <div class="scroll-box" id="scrolling" *ngIf="data.type === 'resource'">
           <div class="detail-info" *ngIf="!notebook.error_message">
-            <p>Edge Node IP Address {{notebook.node_ip}}</p>
+            <p>Edge Node IP Address {{notebook.node_ip}}  </p>
             <p *ngIf="notebook.status === 'running'">Up time {{upTimeInHours}} hour(s) since
-              {{notebook.time ? (notebook.time | longDate ) : "not specified."}}
+              {{notebook.time ? (notebook.time | longDate) : "not specified."}}
             </p>
             <p *ngIf="notebook.url?.length">Open following URL(s) in your browser to access this box:</p>
             <div class="links_block">
               <ng-container *ngFor="let item of notebook.url">
-                <span 
-                  class="d-none" 
-                  *ngIf="item.description.toLowerCase() === 'ungit' 
+                <span
+                  class="d-none"
+                  *ngIf="item.description.toLowerCase() === 'ungit'
                     && notebook.template_name.toLowerCase().indexOf('zeppelin ') !== -1; else ungit"
                 ></span>
                 <ng-template #ungit>
                   <p (mouseleave)="hideCopyIcon()">
                     <span class="description">{{item.description}}: &nbsp;</span>
-                    <a 
+                    <a
                       (mouseover)="showCopyIcon(item.description)"
                       (click)="logAction(notebook.name, item.description)"
                       class="ellipsis none-select resources-url" matTooltip="{{item.url}}"
@@ -129,13 +129,13 @@
                       target="_blank"
                       (contextmenu)="false"
                     >
-                      &nbsp;{{item.url}}
+                      &nbsp;{{item.url | truncateTextPipe: urlMaxLength}}
                     </a>
-                    <span 
-                      (click)="logAction(notebook.name, item.description, 'Copy');$event.stopPropagation()" 
-                      *ngIf="isCopyIconVissible[item.description]" 
-                      [matTooltip]="isCopied ? 'Copy ' + item.description + ' url': 'Copied'" 
-                      matTooltipPosition="above" 
+                    <span
+                      (click)="logAction(notebook.name, item.description, 'Copy');$event.stopPropagation()"
+                      *ngIf="isCopyIconVissible[item.description]"
+                      [matTooltip]="isCopied ? 'Copy ' + item.description + ' url': 'Copied'"
+                      matTooltipPosition="above"
                       class="copy-icon-wrapper"
                     >
                       <span  class="link-icon" (click)="copyLink(item.url)" >
@@ -199,7 +199,7 @@
               <!--                 [ngClass]="{'not-allow': !this.bucketStatus['view'] || !thisdata.buckets.length}"-->
               <!--                (click)="bucketBrowser(notebook.bucket_name, notebook.endpoint, this.bucketStatus['view'] && thisdata.buckets.length)"-->
               <!--              >-->
-              <span 
+              <span
                 class="description open-bucket"
                 [matTooltip]="!this.bucketStatus['view']
                   ? 'You have not permission to open bucket'
@@ -209,8 +209,8 @@
                 [matTooltipClass]="'full-size-tooltip'"
                 [ngClass]="{'not-allow': !this.bucketStatus['view'] || !this.data.buckets.length}"
                 (click)="bucketBrowser(
-                  notebook.cloud_provider !== 'azure' ? notebook.bucket_name : notebook.account_name + '.' + notebook.bucket_name, 
-                  notebook.endpoint, 
+                  notebook.cloud_provider !== 'azure' ? notebook.bucket_name : notebook.account_name + '.' + notebook.bucket_name,
+                  notebook.endpoint,
                   this.bucketStatus['view'] && this.data.buckets.length
                 )"
               >
@@ -265,10 +265,10 @@
                           </p> -->
           </div>
 
-          <div 
-            class="checkbox-group" 
+          <div
+            class="checkbox-group"
             *ngIf="notebook.image !== 'docker.datalab-zeppelin'; else not_support"
-            [hidden]="notebook.status !== 'running' || notebook.image === 'docker.datalab-superset' 
+            [hidden]="notebook.status !== 'running' || notebook.image === 'docker.datalab-superset'
               || notebook.image === 'docker.datalab-jupyterlab'"
           >
             <label>
@@ -277,15 +277,15 @@
             <div class="checkbox-group">
               <form [formGroup]="configurationForm" novalidate>
                 <div class="config-details" *ngIf="configuration?.nativeElement['checked'] || false">
-                  <textarea 
-                    formControlName="configuration_parameters" 
+                  <textarea
+                    formControlName="configuration_parameters"
                     id="config"
-                    placeholder="Cluster configuration template, JSON" 
+                    placeholder="Cluster configuration template, JSON"
                     data-gramm_editor="false"
                   ></textarea>
-                  <span 
+                  <span
                     class="danger_color"
-                    *ngIf="!configurationForm.controls.configuration_parameters.valid 
+                    *ngIf="!configurationForm.controls.configuration_parameters.valid
                       && configurationForm.controls['configuration_parameters'].dirty"
                   >
                     Configuration parameters is not in a valid format
@@ -320,10 +320,10 @@
             <div *ngFor="let url of odahu.url" class="odahu-links">
               <div class="odahu-link">
                 <span class="description">{{url.description }}: &nbsp;</span>
-                <a 
-                  class="ellipsis" 
-                  matTooltip="{{ url.url}}" 
-                  matTooltipPosition="above" 
+                <a
+                  class="ellipsis"
+                  matTooltip="{{ url.url}}"
+                  matTooltipPosition="above"
                   href="{{ url.url}}"
                   target="_blank"
                 >
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.ts
index 2ca7cba..c855f76 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/detail-dialog.component.ts
@@ -50,6 +50,7 @@
   public odahu: any;
   public configurationForm: FormGroup;
   @ViewChild('configurationNode') configuration;
+  urlMaxLength: number = 38;
 
   constructor(
     @Inject(MAT_DIALOG_DATA) public data: any,
@@ -150,10 +151,10 @@
     bucketName = this.isBucketAllowed ? bucketName : this.data.buckets[0].children[0].name;
     // bucketName = 'ofuks-1304-pr2-local-bucket';
     this.dialog.open(BucketBrowserComponent, { data:
-      { 
-        bucket: bucketName, 
-        endpoint: endpoint, 
-        bucketStatus: this.bucketStatus, 
+      {
+        bucket: bucketName,
+        endpoint: endpoint,
+        bucketStatus: this.bucketStatus,
         buckets: this.data.buckets
       },
       panelClass: 'modal-fullscreen' }
@@ -163,7 +164,7 @@
   public showCopyIcon(element) {
     this.isCopyIconVissible[element] = true;
   }
-  
+
   public hideCopyIcon() {
     for (const key in this.isCopyIconVissible) {
       this.isCopyIconVissible[key] = false;
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/index.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/index.ts
index 24ec7c5..db416e1 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/detail-dialog/index.ts
@@ -24,6 +24,7 @@
 import { DetailDialogComponent } from './detail-dialog.component';
 import { DirectivesModule } from '../../../core/directives';
 import {LongDatePipeModule} from '../../../core/pipes/long-date-pipe';
+import { TruncateTextPipeModule } from '../../../core/pipes/truncate-text-pipe';
 
 export * from './detail-dialog.component';
 
@@ -34,7 +35,8 @@
         ReactiveFormsModule,
         MaterialModule,
         DirectivesModule,
-        LongDatePipeModule
+        LongDatePipeModule,
+        TruncateTextPipeModule
     ],
   declarations: [DetailDialogComponent],
   entryComponents: [DetailDialogComponent],
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.html
new file mode 100644
index 0000000..4b06523
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.html
@@ -0,0 +1,44 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<div id="dialog-box" class="dialog__wrapper">
+  <header class="dialog-header">
+    <h4 class="modal-title">{{data.title}}<span
+      *ngIf="data.actionType === actionType.share">: {{data.image.name}}
+      </span>
+    </h4>
+    <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+  </header>
+  <section class="content" [ngClass]="isTerminate ? 'terminate-content' : 'share-content'">
+    <ng-content select="[datalab-share-dialog]">
+    </ng-content>
+    <ng-content select="[datalab-terminate-dialog]">
+    </ng-content>
+    <div *ngIf="!activeTabIndex" class="text-center m-bott-10">
+      <button type="button" class="butt mat-raised-button" (click)="dialogRef.close()">No</button>
+      <button
+        [disabled]="isShareBtnDisabled"
+        type="button"
+        class="butt butt-success mat-raised-button"
+        (click)="dialogRef.close(sharingDataList)">
+        {{confirmBtnName}}
+      </button>
+    </div>
+  </section>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.scss
new file mode 100644
index 0000000..a9d69fe
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.scss
@@ -0,0 +1,32 @@
+/*!
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements.  See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership.  The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License.  You may obtain a copy of the License at
+*
+*   http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+
+.content {
+  margin: 0;
+  padding: 20px 30px;
+  font-weight: 600;
+}
+
+.share-content {
+  height: 327px;
+}
+
+.terminate-content {
+  max-height: 75vh;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.ts
new file mode 100644
index 0000000..5279fef
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.component.ts
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Component, Inject, Input, OnInit } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { ImageActions, ImageActionModalData } from '../../images';
+import { DialogWindowTabConfig, UserData } from './image-action.model';
+
+const CONFIRM_BUTTON_CONFIG = {
+  share: 'Share',
+  terminate: 'Yes'
+};
+
+@Component({
+  selector: 'datalab-image-action-dialog',
+  templateUrl: './image-action-dialog.component.html',
+  styleUrls: ['./image-action-dialog.component.scss']
+})
+export class ImageActionDialogComponent implements OnInit {
+  @Input() activeTabIndex: boolean;
+  @Input() isShareBtnDisabled: Boolean;
+  @Input() sharingDataList: UserData[] = [];
+  @Input() isTerminate: boolean = false;
+
+  readonly actionType: typeof ImageActions = ImageActions;
+
+  confirmBtnName!: string;
+
+  constructor(
+    public dialogRef: MatDialogRef<ImageActionDialogComponent>,
+    @Inject(MAT_DIALOG_DATA) public data: ImageActionModalData,
+  ) { }
+
+  ngOnInit(): void {
+    this.createConfirmBtnName();
+  }
+
+  private createConfirmBtnName(): void {
+    this.confirmBtnName = CONFIRM_BUTTON_CONFIG[this.data.actionType];
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.module.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.module.ts
new file mode 100644
index 0000000..db47226
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action-dialog.module.ts
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { ImageActionDialogComponent } from './image-action-dialog.component';
+import { MaterialModule } from '../../../shared/material.module';
+import { TerminateDialogComponent } from './terminate-dialog/terminate-dialog.component';
+import { ShareDialogComponent } from './share-dialog/share-dialog.component';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { ShareUserDataComponent } from './share-user-data/share-user-data.component';
+import { UnShareWarningComponent } from './unshare-warning/un-share-warning.component';
+
+
+
+@NgModule({
+  declarations: [
+    ImageActionDialogComponent,
+    TerminateDialogComponent,
+    ShareDialogComponent,
+    ShareUserDataComponent,
+    UnShareWarningComponent
+  ],
+  imports: [ CommonModule, MaterialModule, FormsModule, ReactiveFormsModule ],
+  entryComponents: [ TerminateDialogComponent , ShareDialogComponent, UnShareWarningComponent ],
+  exports: [ ImageActionDialogComponent ]
+})
+export class ImageActionDialogModule { }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action.config.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action.config.ts
new file mode 100644
index 0000000..8c76948
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action.config.ts
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export enum SharePlaceholder {
+  groupOrNameSearchInput = 'Enter user login or group name'
+}
+
+export enum UserDataTypeConfig {
+  group = 'GROUP',
+  user = 'USER'
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action.model.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action.model.ts
new file mode 100644
index 0000000..42de04e
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/image-action.model.ts
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export interface DialogWindowTabConfig {
+  shareImage: boolean;
+  shareWith: boolean;
+}
+
+export interface UserData {
+  value: string;
+  type: UserDataType;
+}
+
+export interface ShareDialogData {
+  canBeSharedWith: UserData[];
+  sharedWith: UserData[];
+}
+
+export type UserDataType = 'USER' | 'GROUP';
+
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.component.html
new file mode 100644
index 0000000..dff4a98
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.component.html
@@ -0,0 +1,113 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<datalab-image-action-dialog
+  [activeTabIndex]="activeTabIndex"
+  [sharingDataList]="sharingDataList"
+  [isShareBtnDisabled]="!isShareBtnDisabled"
+>
+
+  <!--  Component subscriptions-->
+  <ng-container *ngIf="(getUserListDataSubscription$ | async)"></ng-container>
+  <ng-container *ngIf="(getUserListDataOnChangeSubscription$ | async)"></ng-container>
+  <ng-container *ngIf="(onInputSubscription$ | async)"></ng-container>
+
+  <div datalab-share-dialog class="dialog__wrapper">
+    <mat-tab-group (selectedTabChange)="onTabTitle( )">
+      <mat-tab>
+        <ng-template mat-tab-label>
+          SHARE IMAGE
+        </ng-template>
+        <ng-template matTabContent>
+          <div class="search-input__wrapper">
+
+            <div class="input__wrapper">
+              <input
+                type="text"
+                class="search-input"
+                [placeholder]="placeholder.groupOrNameSearchInput"
+                [formControl]="addUserDataControl"
+                (change)="onChange()"
+                (input)="onInputKeyDown()"
+                matInput
+                [matAutocomplete]="auto"
+                #searchUserData
+              />
+              <mat-autocomplete #auto="matAutocomplete">
+                <mat-option
+                  *ngFor="let user of (searchUserDataDropdownList$ | async)"
+                  (click)="addUserToTemporaryList(user)"
+                  [value]="user.value">
+                  <mat-icon class="user-data__icon">{{user.type === 'GROUP' ? 'people' : 'person'}}</mat-icon>
+                  {{user.value}}
+                </mat-option>
+                <mat-option *ngIf="!(searchUserDataDropdownList$ | async)?.length" class="multiple-select ml-10" disabled>
+                  No results found
+                </mat-option>
+              </mat-autocomplete>
+              <span [hidden]="!isUserDataListEmpty" class="error">
+          Please enter user login or group name
+        </span>
+            </div>
+            <div class="user-list__wrapper scrolling">
+              <ul class="user-list user-list__temporary">
+                <li
+                  *ngFor="let entity of (temporaryUserDataList$ | async)"
+                  class="user-list__item"
+                >
+                  <datalab-share-user-data
+                    (removeUserData)="onRemoveUserData($event)"
+                    [userData]="entity"
+                  >
+                  </datalab-share-user-data>
+                </li>
+              </ul>
+            </div>
+          </div>
+        </ng-template>
+      </mat-tab>
+      <mat-tab>
+        <ng-template mat-tab-label>
+          SHARED WITH
+        </ng-template>
+        <ng-template matTabContent>
+          <div class="share-with__wrapper">
+            <div
+              *ngIf="(userDataList$ | async)?.length; else emptyUserList"
+              class="user-list__wrapper scrolling"
+            >
+              <ul class="user-list user-list__shared">
+                <li
+                  *ngFor="let entity of (userDataList$ | async)"
+                  class="user-list__item"
+                >
+                  <datalab-share-user-data (removeUserData)="unShare($event)" [userData]="entity"></datalab-share-user-data>
+                </li>
+              </ul>
+
+            </div>
+            <ng-template #emptyUserList>
+              <p class="empty-state">The image hase not been shared.</p>
+            </ng-template>
+          </div>
+        </ng-template>
+      </mat-tab>
+    </mat-tab-group>
+  </div>
+</datalab-image-action-dialog>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.component.scss
new file mode 100644
index 0000000..353df2c
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.component.scss
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+.title{
+  color: #718ba6;
+  font-weight: 400;
+
+  &__list {
+    display: flex;
+    justify-content: space-between;
+    margin-bottom: 30px;
+  }
+
+  &__item {
+    width: 49%;
+    padding: 5px 0;
+    text-align: center;
+    border-bottom: 1px solid rgba(0,0,0,.08);
+  }
+
+  &__btn {
+    width: 100%;
+    background-color: transparent;
+    border: none;
+    outline: none;
+    cursor: pointer;
+  }
+}
+
+.search-input {
+  width: 80%;
+  color: #718ba6;
+  border: none;
+  border-bottom: 1px solid rgba(0,0,0,.08);
+  outline: none;
+
+  &::placeholder {
+    font-size: 16px;
+    color: #c6bcbc;
+    font-weight: 300;
+  }
+
+  &__wrapper {
+    padding-top: 30px;
+  }
+}
+
+.active-tab {
+  background-color: #E9F7FA;
+  border-bottom: 2px solid #35afd5;
+}
+
+.error {
+  font-weight: 200;
+}
+
+.add-person__btn {
+  position: absolute;
+  top: -12px;
+  right: 10px;
+}
+
+.user-list {
+  display: flex;
+  flex-wrap: wrap;
+  padding: 10px 0;
+
+  &__temporary {
+    height: 80px;
+  }
+
+  &__shared {
+    height: 160px;
+  }
+
+  &__wrapper{
+    margin-bottom: 45px;
+    overflow-y: scroll;
+  }
+
+  &__item {
+    position: relative;
+    margin-right: 20px;
+    margin-bottom: 20px;
+  }
+}
+
+.input__wrapper {
+  position: relative;
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  height: 35px;
+}
+
+.empty-state {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 200px;
+  color: #35afd5;
+  font-weight: 300;
+}
+
+.user-data__icon {
+  width: 30px;
+  height: 30px;
+  padding-top: 2px;
+  text-align: center;
+  border-radius: 50%;
+  background-color: #E6E6E6;
+  color: white;
+}
+
+.dialog__wrapper ::ng-deep .mat-tab-label {
+  width: 50%;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.component.ts
new file mode 100644
index 0000000..b1a9c7a
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.component.ts
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Component, ElementRef, Inject, OnDestroy, OnInit, ViewChild } from '@angular/core';
+import { SharePlaceholder } from '../image-action.config';
+import { ShareDialogData, UserData } from '../image-action.model';
+import { FormControl } from '@angular/forms';
+import { MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog';
+import {
+  ImageActionModalData,
+  ModalTitle,
+  Toaster_Message,
+  UnShareModal,
+} from '../../../images';
+import { switchMap, tap } from 'rxjs/operators';
+import { Observable, timer } from 'rxjs';
+import { UnShareWarningComponent } from '../unshare-warning/un-share-warning.component';
+import { ToastrService } from 'ngx-toastr';
+import { ShareDialogService } from './share-dialog.service';
+
+@Component({
+  selector: 'datalab-share-dialog',
+  templateUrl: './share-dialog.component.html',
+  styleUrls: ['./share-dialog.component.scss'],
+})
+
+export class ShareDialogComponent implements OnInit, OnDestroy {
+  @ViewChild('searchUserData') searchUserData: ElementRef;
+
+  readonly placeholder: typeof SharePlaceholder = SharePlaceholder;
+
+  searchUserDataDropdownList$: Observable<UserData[]>;
+  userDataList$!: Observable<UserData[]>;
+  temporaryUserDataList$!: Observable<UserData[]>;
+  sharingDataList: UserData[] = [];
+  activeTabIndex: boolean = false;
+  addUserDataControl: FormControl = new FormControl('');
+
+  onInputSubscription$: Observable<UserData[]>;
+  getUserListDataSubscription$: Observable<ShareDialogData>;
+  getUserListDataOnChangeSubscription$: Observable<UserData[]>;
+
+  constructor(
+    public toastr: ToastrService,
+    @Inject(MAT_DIALOG_DATA) public data: ImageActionModalData,
+    private dialog: MatDialog,
+    private shareDialogService: ShareDialogService
+  ) {
+  }
+
+  ngOnInit(): void {
+    this.getImageParams();
+    this.getUserListDataSubscription$ = this.shareDialogService.getImageShareInfo();
+    this.initUserData();
+    this.initSearchDropdownList();
+    this.initTemporaryUserDataList();
+  }
+
+  ngOnDestroy(): void {
+    this.shareDialogService.clearTemporaryList();
+  }
+
+  onInputKeyDown(): void {
+    this.onInputSubscription$ = timer(300).pipe(
+      switchMap(() => this.shareDialogService.getUserDataForShareDropdown(this.addUserDataControl.value))
+    );
+  }
+
+  onChange(): void {
+    this.addUserDataControl.setValue('');
+    // We need a timer because the click event cannot have time to select userData from the dropdown list.
+    this.getUserListDataOnChangeSubscription$ = timer(300).pipe(
+      switchMap(() => this.shareDialogService.getUserDataForShareDropdown())
+    );
+  }
+
+  addUserToTemporaryList(user: UserData): void {
+    if (!user) {
+      return;
+    }
+    this.shareDialogService.addToTemporaryList(user);
+    this.addUserDataControl.setValue('');
+    this.searchUserData.nativeElement.blur();
+    this.sharingDataList = this.shareDialogService.getSharingUserDataList();
+    this.shareDialogService.filterSearchDropdown();
+  }
+
+  onTabTitle(): void {
+    this.activeTabIndex = !this.activeTabIndex;
+  }
+
+  onRemoveUserData(userData: UserData): void {
+    this.shareDialogService.removeUserFromTemporaryList(userData);
+    this.shareDialogService.filterSearchDropdown();
+  }
+
+  unShare(userData: UserData): void {
+    const data: UnShareModal = {
+      userData,
+      title: ModalTitle.unShare
+    };
+
+    this.getUserListDataSubscription$ = this.dialog.open(UnShareWarningComponent, {
+      data,
+      panelClass: 'modal-sm'
+    }).afterClosed()
+      .pipe(
+        switchMap((isShare) => this.shareDialogService.sendShareRequest(isShare, this.data.image, userData)),
+        switchMap(() =>  this.shareDialogService.getImageShareInfo()),
+        tap(() => this.toastr.success(Toaster_Message.successUnShare, Toaster_Message.successTitle))
+      );
+  }
+
+  private getImageParams(): void {
+    this.shareDialogService.getImageParams(this.data.image);
+  }
+
+  private initUserData(): void {
+    this.userDataList$ = this.shareDialogService.userDataList$;
+  }
+
+  private initSearchDropdownList(): void {
+    this.searchUserDataDropdownList$ = this.shareDialogService.searchUserDataDropdownList$;
+  }
+
+  private initTemporaryUserDataList(): void {
+    this.temporaryUserDataList$ = this.shareDialogService.temporaryUserDataList$;
+  }
+
+  get isShareBtnDisabled(): boolean {
+    return !this.shareDialogService.isTemporaryListEmpty();
+  }
+
+  get isUserDataListEmpty(): boolean {
+    return this.addUserDataControl.touched && this.shareDialogService.isTemporaryListEmpty();
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.service.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.service.ts
new file mode 100644
index 0000000..05f75ae
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-dialog/share-dialog.service.ts
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Injectable } from '@angular/core';
+import { BehaviorSubject, EMPTY, Observable } from 'rxjs';
+import { take, tap } from 'rxjs/operators';
+
+import isEqual from 'lodash.isequal';
+
+import { ImagesService } from '../../../images/images.service';
+import { ImageActionDialogModule } from '../image-action-dialog.module';
+import { ImageModel, ImageParams, ProjectImagesInfo } from '../../../images';
+import { ShareDialogData, UserData } from '../image-action.model';
+
+@Injectable({
+  providedIn: ImageActionDialogModule
+})
+export class ShareDialogService {
+  private searchUserDataDropdownList$$: BehaviorSubject<UserData[]> = new BehaviorSubject<UserData[]>([]);
+  private userDataList$$: BehaviorSubject<UserData[]> = new BehaviorSubject<UserData[]>([]);
+  private temporaryUserDataList$$: BehaviorSubject<UserData[]> = new BehaviorSubject<UserData[]>([]);
+  private cashedUserDataDropdownList: UserData[];
+
+  searchUserDataDropdownList$: Observable<UserData[]> = this.searchUserDataDropdownList$$.asObservable();
+  userDataList$: Observable<UserData[]> = this.userDataList$$.asObservable();
+  temporaryUserDataList$: Observable<UserData[]> = this.temporaryUserDataList$$.asObservable();
+  imageInfo: ImageParams;
+
+  constructor(
+    private imagesService: ImagesService,
+  ) { }
+
+  getUserDataForShareDropdown(userData: string = ''): Observable<UserData[]> {
+    return this.imagesService.getUserDataForShareDropdown(userData, this.imageInfo)
+      .pipe(
+        tap(response => this.filterSearchDropdown(response))
+      );
+  }
+
+  sendShareRequest(flag: boolean, image: ImageModel, userData: UserData): Observable<ProjectImagesInfo> {
+    const filteredList = this.filterSharingList(userData);
+    const imageInfo = this.imagesService.createImageRequestInfo(image, filteredList);
+    if (!flag) {
+      return EMPTY;
+    }
+    return  this.imagesService.shareImageAllUsers(imageInfo);
+  }
+
+  getImageShareInfo(): Observable<ShareDialogData> {
+    return this.imagesService.getImageShareInfo(this.imageInfo).pipe(
+      tap(({canBeSharedWith, sharedWith}) => {
+        this.cashedUserDataDropdownList = canBeSharedWith;
+        this.searchUserDataDropdownList$$.next(canBeSharedWith);
+        this.userDataList$$.next(sharedWith);
+      }),
+      take(1)
+    );
+  }
+
+  filterSharingList(userData: UserData): UserData[] {
+    return this.userDataList$$.value.filter(item => !isEqual(item, userData));
+  }
+
+  getSharingUserDataList(): UserData[] {
+    return [...this.userDataList$$.value, ...this.temporaryUserDataList$$.value];
+  }
+
+  addToTemporaryList(user: UserData): void {
+    const filteredList = [...this.temporaryUserDataList$$.value, user]
+      .sort((a, b) => a.value < b.value ? 1 : -1)
+      .sort((a, b) => a.type > b.type ? 1 : -1);
+    this.temporaryUserDataList$$.next(filteredList);
+  }
+
+  isTemporaryListEmpty(): boolean {
+    return !Boolean(this.temporaryUserDataList$$.value.length);
+  }
+
+  clearTemporaryList(): void {
+    this.temporaryUserDataList$$.next([]);
+  }
+
+  removeUserFromTemporaryList(userData: UserData): void {
+    const filteredList = this.temporaryUserDataList$$.value.filter(item => !isEqual(item, userData));
+    this.temporaryUserDataList$$.next(filteredList);
+  }
+
+  filterSearchDropdown(userData: UserData[] = this.cashedUserDataDropdownList): void {
+   const filteredDropdownList = userData.filter(item => !this.getSharingUserDataList()
+     .some(temporaryDataItem => isEqual(item, temporaryDataItem))
+   );
+    this.searchUserDataDropdownList$$.next(filteredDropdownList);
+  }
+
+  getImageParams(image: ImageModel): void {
+    this.imageInfo = this.imagesService.createImageRequestInfo(image);
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-user-data/share-user-data.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-user-data/share-user-data.component.html
new file mode 100644
index 0000000..f8c8a58
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-user-data/share-user-data.component.html
@@ -0,0 +1,25 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<div class="user-data__wrapper">
+  <span><mat-icon class="user-data__icon">{{userData.type === 'GROUP' ? 'people' : 'person'}}</mat-icon></span>
+  <span class="user-data__name">{{userData.value}}
+    <button type="button" (click)="removeUser(userData)" class="close-btn">&times;</button>
+</span>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-user-data/share-user-data.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-user-data/share-user-data.component.scss
new file mode 100644
index 0000000..8b776b3
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-user-data/share-user-data.component.scss
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+.user-data {
+  &__name {
+    position: relative;
+    padding: 2px 25px 2px 10px;
+    font-size: 13px;
+    font-weight: 400;
+    border-radius: 5px;
+  }
+
+  &__icon {
+    position: absolute;
+    top: -5px;
+    left: 0;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    width: 30px;
+    height: 30px;
+    color: white;
+    font-size: 18px;
+    border-radius: 50%;
+  }
+
+  &__icon,
+  &__name {
+    background-color: #D3F0F4;
+  }
+
+  &__wrapper {
+    position: relative;
+    padding-left: 24px;
+  }
+}
+
+.close-btn {
+  position: absolute;
+  top: 2px;
+  right: 8px;
+  background-color: transparent;
+  border: none;
+  outline: none;
+  cursor: pointer;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-user-data/share-user-data.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-user-data/share-user-data.component.ts
new file mode 100644
index 0000000..ba52a47
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/share-user-data/share-user-data.component.ts
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+import { UserData } from '../image-action.model';
+
+@Component({
+  selector: 'datalab-share-user-data',
+  templateUrl: './share-user-data.component.html',
+  styleUrls: ['./share-user-data.component.scss'],
+})
+export class ShareUserDataComponent {
+  @Input() userData: UserData;
+
+  @Output() removeUserData: EventEmitter<UserData> = new EventEmitter<UserData>();
+
+  removeUser(userData: UserData): void {
+    this.removeUserData.emit(userData);
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component.html
new file mode 100644
index 0000000..d52209e
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component.html
@@ -0,0 +1,37 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<datalab-image-action-dialog [isTerminate]="true">
+  <div datalab-terminate-dialog class="wrapper">
+    <div  class="terminate-action__wrapper">
+      <div class="list-header sans terminate-action__header--wrapper">
+        <div class="image">Image</div>
+        <div class="status">Further status</div>
+      </div>
+      <div class="scrolling-content scrolling terminate-image-list__wrapper">
+        <div class="image-name ellipsis">{{data.image.name}}</div>
+        <div class="status terminated">Terminated</div>
+      </div>
+      <p *ngIf="data.isShared" class="shared-warning">!The image is shared with other users.</p>
+    </div>
+    <p class="question">
+      Do you want proceed?
+    </p>
+  </div>
+</datalab-image-action-dialog>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component.scss
new file mode 100644
index 0000000..29e2e10
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component.scss
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+.terminate-action__wrapper {
+  width: 100%;
+}
+
+.terminate-image-list__wrapper {
+  margin-bottom: 10px;
+  border-bottom: 1px solid rgba(0,0,0,.08);
+}
+
+.terminate-action__header--wrapper,
+.terminate-image-list__wrapper {
+  display: flex;
+  justify-content: space-between;
+  padding: 10px 20px;
+  line-height: 26px;
+
+  & > .status {
+    text-align: right;
+  }
+}
+
+.terminate-action__header--wrapper {
+  margin-top: 26px;
+}
+
+.wrapper {
+  & .terminate-image-list__wrapper {
+    & > .status {
+      font-weight: 300;
+    }
+  }
+}
+
+.shared-warning {
+  margin-bottom: 10px;
+  color: red;
+  text-align: center;
+  font-weight: 400;
+}
+
+.question,
+.shared-warning {
+  line-height: 1;
+}
+
+.question {
+  margin-bottom: 30px;
+  text-align: center;
+  color: #718ba6;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component.ts
new file mode 100644
index 0000000..d15a3d4
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component.ts
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Component, Inject } from '@angular/core';
+import { MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { ImageActionModalData } from '../../../images';
+
+@Component({
+  selector: 'datalab-terminate-dialog',
+  templateUrl: './terminate-dialog.component.html',
+  styleUrls: ['./terminate-dialog.component.scss']
+})
+export class TerminateDialogComponent {
+
+  constructor(
+    @Inject(MAT_DIALOG_DATA) public data: ImageActionModalData,
+  ) { }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/unshare-warning/un-share-warning.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/unshare-warning/un-share-warning.component.html
new file mode 100644
index 0000000..b1c9cfa
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/unshare-warning/un-share-warning.component.html
@@ -0,0 +1,41 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<div id="dialog-box" class="dialog__wrapper">
+  <header class="dialog-header">
+    <h4 class="modal-title">{{data.title}}
+    </h4>
+    <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+  </header>
+  <section class="content">
+    <p class="modal__text"><span>{{data.userData.type | titlecase}} </span> <span class="user__name">{{data.userData.value}}</span> will no longer have an access to the image.</p>
+    <p class="question center">
+      Do you want proceed?
+    </p>
+  </section>
+  <div class="text-center m-top-30 m-bott-10 button__wrapper">
+    <button type="button" class="butt mat-raised-button" (click)="dialogRef.close()">No</button>
+    <button
+      type="button"
+      class="butt butt-success mat-raised-button"
+      (click)="dialogRef.close(true)">
+      Yes
+    </button>
+  </div>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/unshare-warning/un-share-warning.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/unshare-warning/un-share-warning.component.scss
new file mode 100644
index 0000000..f4d9041
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/unshare-warning/un-share-warning.component.scss
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+.content {
+  padding: 20px 50px 0 50px;
+}
+
+.user__name {
+  font-weight: bold;
+}
+
+.modal__text {
+  text-align: center;
+  color: #35afd5;
+  margin-bottom: 30px;
+}
+
+.question {
+  text-align: center;
+  color: #718ba6;
+  font-weight: bold;
+}
+
+.button__wrapper {
+  margin-bottom: 20px;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/unshare-warning/un-share-warning.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/unshare-warning/un-share-warning.component.ts
new file mode 100644
index 0000000..36c1e9c
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-action-dialog/unshare-warning/un-share-warning.component.ts
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Component, Inject } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { UnShareModal } from '../../../images';
+
+@Component({
+  templateUrl: './un-share-warning.component.html',
+  styleUrls: ['./un-share-warning.component.scss']
+})
+export class UnShareWarningComponent {
+
+  constructor(
+    public dialogRef: MatDialogRef<UnShareWarningComponent>,
+    @Inject(MAT_DIALOG_DATA) public data: UnShareModal,
+  ) { }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-detail-dialog/image-detail-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-detail-dialog/image-detail-dialog.component.html
new file mode 100644
index 0000000..bb9ad37
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-detail-dialog/image-detail-dialog.component.html
@@ -0,0 +1,103 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<div class="detail-dialog" id="dialog-box">
+  <header class="dialog-header header-white">
+    <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+  </header>
+
+  <div>
+    <table class="detail-header">
+      <tr>
+        <td>{{ data.image.name }}</td>
+        <td>{{ data.image.project }}</td>
+        <td>
+            <span class="status" [ngClass]="data.image.status.toLowerCase()">
+              {{ data.image.status | titlecase }}
+            </span>
+        </td>
+      </tr>
+    </table>
+
+    <div class="content-box">
+      <div *ngIf="data.image.description" class="image__description--wrapper">
+        <p
+          [matTooltip]="data.image.description"
+          matTooltipPosition="above"
+          [matTooltipDisabled]="data.image.description.length < maxDescriptionLength"
+          class="image__description">
+          {{ data.image.description | truncateTextPipe : maxDescriptionLength}}
+        </p>
+      </div>
+
+      <div class="image__template--wrapper">
+        <span class="modal-row__item modal-row__item--title">Template name</span>
+        <span class="modal-row__item">{{ data.image.templateName }}</span>
+      </div>
+
+      <div class="image__libraries--wrapper">
+        <span class="modal-row__item modal-row__item--title">Installed libraries' groups</span>
+        <div class="language__wrapper modal-row__item">
+          <div *ngIf="libraryList.length; else notAvailable">
+            <div *ngFor="let library of libraryList" class="library__wrapper">
+              <span>{{library.name | libNameNormalize}}</span>
+              <i (click)="onLibraryInfo(library)" class="material-icons library__info">info</i>
+            </div>
+          </div>
+          <ng-template #notAvailable>
+            <span class="no-libraries">No additional libraries installed</span>
+          </ng-template>
+        </div>
+      </div>
+
+      <div class="image__provider--wrapper">
+        <span class="modal-row__item modal-row__item--title">Provider</span>
+        <span class="modal-row__item">{{ data.image.cloudProvider }}</span>
+      </div>
+
+      <div class="image__creation-date--wrapper">
+        <span class="modal-row__item modal-row__item--title">Creation date</span>
+        <span class="modal-row__item">{{data.image.timestamp | localDate : 'short'}} </span>
+      </div>
+
+      <div class="image__creator--wrapper">
+        <span class="modal-row__item modal-row__item--title">Creator</span>
+        <span class="modal-row__item">{{ data.image.user }}</span>
+      </div>
+
+      <div *ngIf="data.image.sharingStatus === sharingStatus.shared" class="image__creator--wrapper">
+        <span class="modal-row__item modal-row__item--title">Shared with</span>
+        <div class="user-data__list--wrapper scrolling">
+          <ul class="groups__list">
+            <li *ngFor="let group of sortedShareWith.groups" class="groups__item">
+              <span class="icon--wrapper"><mat-icon class="user-data__icon">people</mat-icon></span>
+              <span class="groups__item--wrapper">{{group}}</span>
+            </li>
+          </ul>
+          <ul class="users__list">
+            <li *ngFor="let user of sortedShareWith.users" class="users__item">
+              <span class="icon--wrapper"><mat-icon class="user-data__icon">person</mat-icon></span>
+              <span class="groups__item--wrapper">{{user}}</span>
+            </li>
+          </ul>
+        </div>
+      </div>
+    </div>
+  </div>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-detail-dialog/image-detail-dialog.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-detail-dialog/image-detail-dialog.component.scss
new file mode 100644
index 0000000..ebcc1d6
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-detail-dialog/image-detail-dialog.component.scss
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+.image__description {
+  font-size: 12px;
+  text-align: justify;
+}
+
+.content-box > div {
+  display: flex;
+  justify-content: space-between;
+  padding: 10px 0;
+
+  &:not(:last-child) {
+    border-bottom: 1px solid #edf1f5;
+  }
+
+  &.image__description--wrapper {
+    padding: 0 0 10px 0;
+  }
+}
+
+.modal-row__item {
+  width: 50%;
+
+  &--title {
+    font-weight: 500;
+  }
+}
+
+.library {
+  &__wrapper {
+    display: flex;
+    justify-content: space-between;
+
+    &:not(:last-child) {
+      margin-bottom: 10px;
+    }
+  }
+
+  &__info {
+    cursor: pointer;
+  }
+}
+
+.no-libraries {
+  color: rgba(113, 138, 165, 0.5);
+}
+
+.users__item,
+.groups__item {
+  display: flex;
+  align-items: center;
+
+  &:not(last-child) {
+    margin-bottom: 10px;
+  }
+}
+
+.user-data {
+
+  &__icon {
+    border-radius: 50%;
+  }
+
+  &__list--wrapper {
+    width: 50%;
+    height: 110px;
+    overflow-y: scroll;
+  }
+}
+
+.icon--wrapper {
+  margin-right: 10px;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-detail-dialog/image-detail-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-detail-dialog/image-detail-dialog.component.ts
new file mode 100644
index 0000000..699a2f4
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-detail-dialog/image-detail-dialog.component.ts
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Component, Inject, OnInit } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog';
+import { LibraryInfoItem, Library, ImageDetailModalData, SharingStatus, SharedWithField } from '../../images';
+import { LibraryInfoModalComponent } from '../library-info-modal/library-info-modal.component';
+import { caseInsensitiveSortUtil } from '../../../core/util';
+
+@Component({
+  selector: 'datalab-image-detail-dialog',
+  templateUrl: './image-detail-dialog.component.html',
+  styleUrls: [
+    './image-detail-dialog.component.scss',
+    '../detail-dialog/detail-dialog.component.scss'
+  ]
+})
+
+export class ImageDetailDialogComponent implements OnInit {
+  readonly sharingStatus: typeof SharingStatus = SharingStatus;
+
+  maxDescriptionLength: number = 170;
+  libraryList = [];
+  sortedShareWith: SharedWithField;
+
+  constructor(
+    public dialogRef: MatDialogRef<ImageDetailDialogComponent>,
+    @Inject(MAT_DIALOG_DATA) public data: ImageDetailModalData,
+    private dialog: MatDialog,
+  ) { }
+
+  ngOnInit(): void {
+    this.libraryList = this.normalizeLibraries();
+    this.sortedShareWith = this.sortUserData();
+  }
+
+  onLibraryInfo(libraryList): void {
+    this.dialog.open(LibraryInfoModalComponent, {
+      data: {
+        libraryList
+      },
+      panelClass: 'library-dialog-container'
+    });
+  }
+
+  private normalizeLibraries(): LibraryInfoItem[] {
+    return this.data.image.libraries.reduce((acc, item) => {
+      const libraryName = this.normalizeLibraryName(item);
+      const isLibAdded = acc.find(({name}) => item.group === name);
+      if (!isLibAdded) {
+        const newLibrary: LibraryInfoItem = {
+          name: item.group,
+          libs: [`${libraryName} v ${item.version}`]
+        };
+        acc.push(newLibrary);
+      } else {
+        acc.find(({name}) => item.group === name).libs.push(`${libraryName} v ${item.version}`);
+      }
+      return acc;
+    }, [])
+      .map(item => {
+        caseInsensitiveSortUtil(item.libs);
+        return item;
+    });
+  }
+
+  private normalizeLibraryName(library: Library): string {
+    if (library.group === 'java') {
+      const [, libName] = library.name.split(':');
+      return libName;
+    }
+    return library.name;
+  }
+
+  private sortUserData(): SharedWithField {
+    const { groups, users } = this.data.image.sharedWith;
+    return {
+      users: this.sortUserDataByValue(users),
+      groups: this.sortUserDataByValue(groups),
+    };
+  }
+
+  private sortUserDataByValue(arr: string[]): string[] {
+    return arr.sort((a, b) => a.toLowerCase() > b.toLowerCase() ? 1 : -1);
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-detail-dialog/image-detail-dialog.module.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-detail-dialog/image-detail-dialog.module.ts
new file mode 100644
index 0000000..d4e215a
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/image-detail-dialog/image-detail-dialog.module.ts
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { ImageDetailDialogComponent } from './image-detail-dialog.component';
+import { TruncateTextPipeModule } from '../../../core/pipes/truncate-text-pipe';
+import {LocalDatePipeModule} from '../../../core/pipes/local-date-pipe';
+import {MatTooltipModule} from '@angular/material/tooltip';
+import {LibraryNameNormalizePipeModule} from '../../../core/pipes/library-name-normalize';
+import { MaterialModule } from '../../../shared/material.module';
+
+
+
+@NgModule({
+  declarations: [ ImageDetailDialogComponent ],
+    imports: [
+        CommonModule,
+        TruncateTextPipeModule,
+        LocalDatePipeModule,
+        MatTooltipModule,
+        LibraryNameNormalizePipeModule,
+        MaterialModule,
+    ],
+  exports: [ ImageDetailDialogComponent ],
+  entryComponents: [ ImageDetailDialogComponent ]
+})
+export class ImageDetailDialogModule { }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.ts
index 8a867e9..2448619 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.ts
@@ -22,7 +22,7 @@
 import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
 import { FormControl } from '@angular/forms';
 import { ToastrService } from 'ngx-toastr';
-import {debounceTime, filter, take, takeUntil} from 'rxjs/operators';
+import {debounceTime, take, takeUntil} from 'rxjs/operators';
 
 import { InstallLibrariesModel } from './install-libraries.model';
 import { LibrariesInstallationService } from '../../../core/services';
@@ -112,8 +112,8 @@
       takeUntil(this.unsubscribe$)
       )
       .subscribe(value => {
-        if(!!value?.match(/\s+/g)) {
-          this.libSearch.setValue(value.replace(/\s+/g, ''))
+        if (!!value?.match(/\s+/g)) {
+          this.libSearch.setValue(value.replace(/\s+/g, ''));
           this.lib.name = value.replace(/\s+/g, '');
         } else {
           this.lib.name = value;
@@ -159,6 +159,7 @@
     this.notebook.type = 'EXPLORATORY';
     this.notebook.title = `${this.notebook.name} <em class="capt">notebook</em>`;
     return [this.notebook].concat(this.notebook.resources
+      .filter((item) => !Boolean(item.hdinsight_version))
       .filter(item => item.status === 'running')
       .map(item => {
         item['name'] = item.computational_name;
@@ -170,14 +171,14 @@
 
   public filterList(): void {
     this.validity_format = '';
-    (this.lib.name && this.lib.name.length >= 2 && this.group ) 
-      ? this.getFilteredList() 
+    (this.lib.name && this.lib.name.length >= 2 && this.group )
+      ? this.getFilteredList()
       : this.filteredList = null;
   }
 
   public filterGroups(groupsList): Array<string> {
     const CURRENT_TEMPLATE = this.notebook.template_name.toLowerCase();
-    if (CURRENT_TEMPLATE.indexOf('jupyter with tensorflow') !== -1  
+    if (CURRENT_TEMPLATE.indexOf('jupyter with tensorflow') !== -1
       || CURRENT_TEMPLATE.indexOf('deep learning') !== -1) {
       const filtered = groupsList.filter(group => group !== 'r_pkg');
       return SortUtils.libGroupsSort(filtered);
@@ -217,7 +218,7 @@
     this.checkFilters();
   }
 
-  private checkFilters() : void{
+  private checkFilters(): void {
     this.isFilterChanged = CompareUtils.compareFilters(this.filterModel, this.cashedFilterForm);
     this.isFilterSelected = Object.keys(this.filterModel).some(v => this.filterModel[v].length > 0);
   }
@@ -499,22 +500,22 @@
       Object.setPrototypeOf(this.cashedFilterForm, Object.getPrototypeOf(this.filterModel));
     }
     this.filtredNotebookLibs = this.notebookLibs.filter((lib) => {
-      const isName = this.cashedFilterForm.name 
+      const isName = this.cashedFilterForm.name
         ? lib.name.toLowerCase().indexOf(this.cashedFilterForm.name.toLowerCase().trim()) !== -1
-          || lib.version.indexOf(this.cashedFilterForm.name.toLowerCase().trim()) !== -1 
+          || lib.version.indexOf(this.cashedFilterForm.name.toLowerCase().trim()) !== -1
         : true;
-      const isGroup = this.cashedFilterForm.group.length 
-        ? this.cashedFilterForm.group.includes(this.groupsListMap[lib.group]) 
+      const isGroup = this.cashedFilterForm.group.length
+        ? this.cashedFilterForm.group.includes(this.groupsListMap[lib.group])
         : true;
       lib.filteredStatus = lib.status.filter(status => {
-        const isResource = this.cashedFilterForm.resource.length 
-          ? this.cashedFilterForm.resource.includes(status.resource) 
+        const isResource = this.cashedFilterForm.resource.length
+          ? this.cashedFilterForm.resource.includes(status.resource)
           : true;
-        const isResourceType = this.cashedFilterForm.resource_type.length 
-          ? this.cashedFilterForm.resource_type.includes(status.resourceType) 
+        const isResourceType = this.cashedFilterForm.resource_type.length
+          ? this.cashedFilterForm.resource_type.includes(status.resourceType)
           : true;
-        const isStatus = this.cashedFilterForm.status.length 
-          ? this.cashedFilterForm.status.includes(status.status) 
+        const isStatus = this.cashedFilterForm.status.length
+          ? this.cashedFilterForm.status.includes(status.status)
           : true;
         return isResource && isResourceType && isStatus;
       });
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/library-info-modal/library-info-modal.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/library-info-modal/library-info-modal.component.html
new file mode 100644
index 0000000..2e641d8
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/library-info-modal/library-info-modal.component.html
@@ -0,0 +1,31 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<div class="detail-dialog" id="dialog-box">
+  <header class="dialog-header">
+    <h1 class="modal__title">Installed libraries</h1>
+    <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+  </header>
+
+  <div class="content-box">
+    <div class="library__wrapper" *ngFor="let library of data.libraryList.libs">
+      <span>{{library}}</span>
+    </div>
+  </div>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/library-info-modal/library-info-modal.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/library-info-modal/library-info-modal.component.scss
new file mode 100644
index 0000000..e7e365b
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/library-info-modal/library-info-modal.component.scss
@@ -0,0 +1,22 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+.modal__title {
+  font-size: 12px;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/library-info-modal/library-info-modal.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/library-info-modal/library-info-modal.component.ts
new file mode 100644
index 0000000..93e8954
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/library-info-modal/library-info-modal.component.ts
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Component, Inject } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+
+@Component({
+  selector: 'datalab-library-info-modal',
+  templateUrl: './library-info-modal.component.html',
+  styleUrls: [
+    './library-info-modal.component.scss',
+    '../detail-dialog/detail-dialog.component.scss'
+  ]
+})
+export class LibraryInfoModalComponent {
+
+  constructor(
+    public dialogRef: MatDialogRef<LibraryInfoModalComponent>,
+    @Inject(MAT_DIALOG_DATA) public data: any,
+  ) { }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/library-info-modal/library-info-modal.module.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/library-info-modal/library-info-modal.module.ts
new file mode 100644
index 0000000..80cd1f8
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/library-info-modal/library-info-modal.module.ts
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import {LibraryInfoModalComponent} from './library-info-modal.component';
+
+
+
+@NgModule({
+  declarations: [LibraryInfoModalComponent],
+  imports: [
+    CommonModule
+  ],
+  exports: [LibraryInfoModalComponent],
+  entryComponents: [LibraryInfoModalComponent]
+})
+export class LibraryInfoModalModule { }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/page-filter/page-filter.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/page-filter/page-filter.component.html
new file mode 100644
index 0000000..62fce43
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/page-filter/page-filter.component.html
@@ -0,0 +1,214 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<div class="dialog-content selection">
+
+  <ng-container *ngIf="setFilterValueObservable$ | async"></ng-container>
+  <ng-container *ngIf="changeIsApplyBtnDisabledObservable$ | async"></ng-container>
+
+  <div id="scrolling" class="mat-reset">
+    <form class="filter-table__wrapper" [formGroup]="filterForm">
+      <div class="form-control__wrapper control-group">
+        <label class="label">Image name</label>
+        <input
+          type="text"
+          class="form-control"
+          [placeholder]="placeholders.imageName"
+          [formControlName]="controlNames.imageName"
+          matInput
+          [matAutocomplete]="auto"
+        />
+        <mat-autocomplete autoActiveFirstOption #auto="matAutocomplete">
+          <mat-option *ngFor="let option of (filterDropdownData$ | async).imageNames" [value]="option">
+            {{option}}
+          </mat-option>
+        </mat-autocomplete>
+      </div>
+
+      <div class="control-group">
+        <label class="label">Status</label>
+        <div class="control selector-wrapper">
+            <span class="form-field-wrapper">
+              <mat-form-field (click)="onSelectClick()">
+                <mat-select
+                  [formControlName]="dropdownFieldNames.statuses"
+                  disableOptionCentering
+                  panelClass="create-resources-dialog scrolling"
+                  [placeholder]="placeholders.status"
+                  multiple
+                >
+                  <mat-select-trigger class="select__value">
+                    {{statuses.value | normalizeDropdownMultiValue: selectAllValue | titlecase}}
+                  </mat-select-trigger>
+                  <mat-option
+                    *ngIf="(filterDropdownData$ | async).statuses.length > 1"
+                    #allStatusesSelected
+                    [value]="selectAllValue"
+                    (click)="onClickAll(statuses, allStatusesSelected, dropdownFieldNames.statuses)"
+                  >
+                   All
+                  </mat-option>
+                  <mat-option
+                    *ngFor="let status of (filterDropdownData$ | async).statuses"
+                    [ngClass]="{'single-option': (filterDropdownData$ | async).statuses.length === 1}"
+                    [value]="status"
+                  >
+                    {{ status | titlecase }}
+                  </mat-option>
+                </mat-select>
+                <button class="caret">
+                  <i class="material-icons">keyboard_arrow_down</i>
+                </button>
+              </mat-form-field>
+            </span>
+        </div>
+      </div>
+
+      <div class="control-group">
+        <label class="label">Endpoint</label>
+        <div class="control selector-wrapper">
+            <span class="form-field-wrapper">
+              <mat-form-field (click)="onSelectClick()">
+                <mat-select
+                  [formControlName]="dropdownFieldNames.endpoints"
+                  disableOptionCentering
+                  panelClass="create-resources-dialog scrolling"
+                  [placeholder]="placeholders.endpoint"
+                  multiple
+                >
+                  <mat-select-trigger class="select__value">
+                    {{endpoints.value | normalizeDropdownMultiValue: selectAllValue}}
+                  </mat-select-trigger>
+                  <mat-option
+                    *ngIf="(filterDropdownData$ | async).endpoints.length > 1"
+                    #allEndpointsSelected
+                    [value]="selectAllValue"
+                    (click)="onClickAll(endpoints, allEndpointsSelected, dropdownFieldNames.endpoints)"
+                  >
+                   All
+                  </mat-option>
+                  <mat-option
+                    *ngFor="let endpoint of (filterDropdownData$ | async).endpoints"
+                    [ngClass]="{'single-option': (filterDropdownData$ | async).statuses.length === 1}"
+                    [value]="endpoint"
+                  >
+                    {{ endpoint }}
+                  </mat-option>
+                </mat-select>
+                <button class="caret">
+                  <i class="material-icons">keyboard_arrow_down</i>
+                </button>
+              </mat-form-field>
+            </span>
+        </div>
+      </div>
+
+      <div class="control-group">
+        <label class="label">Template name</label>
+        <div class="control selector-wrapper">
+            <span class="form-field-wrapper">
+              <mat-form-field (click)="onSelectClick()">
+                <mat-select
+                  [formControlName]="dropdownFieldNames.templateNames"
+                  disableOptionCentering
+                  panelClass="create-resources-dialog scrolling"
+                  [placeholder]="placeholders.templateName"
+                  multiple
+                >
+                  <mat-select-trigger class="select__value">
+                    {{templateNames.value | normalizeDropdownMultiValue: selectAllValue}}
+                  </mat-select-trigger>
+                  <mat-option
+                    *ngIf="(filterDropdownData$ | async).templateNames.length > 1"
+                    #allTemplatesSelected
+                    [value]="selectAllValue"
+                    (click)="onClickAll(templateNames, allTemplatesSelected, dropdownFieldNames.templateNames)"
+                  >
+                   All
+                  </mat-option>
+                  <mat-option
+                    *ngFor="let template of (filterDropdownData$ | async).templateNames"
+                    [ngClass]="{'single-option': (filterDropdownData$ | async).statuses.length === 1}"
+                    [value]="template"
+                  >
+                    {{ template }}
+                  </mat-option>
+                </mat-select>
+                <button class="caret">
+                  <i class="material-icons">keyboard_arrow_down</i>
+                </button>
+              </mat-form-field>
+            </span>
+        </div>
+      </div>
+
+      <div class="control-group">
+        <label class="label">Sharing</label>
+        <div class="control selector-wrapper">
+            <span class="form-field-wrapper">
+              <mat-form-field (click)="onSelectClick()">
+                <mat-select
+                  [formControlName]="dropdownFieldNames.sharingStatuses"
+                  disableOptionCentering
+                  panelClass="create-resources-dialog scrolling"
+                  [placeholder]="placeholders.sharing"
+                  multiple
+                >
+                  <mat-select-trigger class="select__value">
+                    {{sharingStatuses.value | normalizeDropdownMultiValue: selectAllValue | titlecase}}
+                  </mat-select-trigger>
+                  <mat-option
+                    *ngIf="(filterDropdownData$ | async).sharingStatuses.length > 1"
+                    #allSharingStatusesSelected
+                    [value]="selectAllValue"
+                    (click)="onClickAll(sharingStatuses, allSharingStatusesSelected, dropdownFieldNames.sharingStatuses)"
+                  >
+                   All
+                  </mat-option>
+                  <mat-option
+                    *ngFor="let status of (filterDropdownData$ | async).sharingStatuses"
+                    [ngClass]="{'single-option': (filterDropdownData$ | async).statuses.length === 1}"
+                    [value]="status"
+                  >
+                    {{ status | titlecase }}
+                  </mat-option>
+                </mat-select>
+                <button class="caret">
+                  <i class="material-icons">keyboard_arrow_down</i>
+                </button>
+              </mat-form-field>
+            </span>
+        </div>
+      </div>
+
+      <div class="text-center m-top-20">
+        <button type="button" class="butt" mat-raised-button (click)="cancelFilter()" >Cancel</button>
+        <button
+          type="button"
+          [disabled]="(isApplyBtnDisabled$ | async)"
+          class="butt butt-success"
+          mat-raised-button
+          (click)="confirmFilter()"
+        >
+          Apply
+        </button>
+      </div>
+    </form>
+  </div>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/page-filter/page-filter.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/page-filter/page-filter.component.scss
new file mode 100644
index 0000000..343e776
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/page-filter/page-filter.component.scss
@@ -0,0 +1,67 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+.filter-table__wrapper {
+  width: 485px;
+  padding: 20px 20px 30px;
+  background-color: white;
+}
+
+.filter-table__wrapper,
+.form-control {
+  box-shadow: 0 3px 1px -2px rgb(0 0 0 / 20%), 0 2px 2px 0 rgb(0 0 0 / 14%), 0 1px 5px 0 rgb(0 0 0 / 12%);
+}
+
+.form-control {
+  padding: 8px;
+
+  &__wrapper {
+    & > .label {
+      width: 35%;
+    }
+
+    & > .form-control {
+      width: 65%;
+    }
+  }
+}
+
+.form-field-wrapper {
+  width: 100%;
+}
+
+::ng-deep .cdk-overlay-pane.normalized-dropdown-position {
+  transform: translateX(-15px) !important;
+}
+
+::ng-deep .cdk-overlay-pane.normalized-dropdown-position {
+  &  .mat-option:first-child .mat-pseudo-checkbox {
+    display: block;
+  }
+}
+
+::ng-deep .cdk-overlay-pane.normalized-dropdown-position {
+  &  .mat-option:first-child.single-option .mat-pseudo-checkbox {
+    display: none;
+  }
+}
+
+.select__value {
+  color: #607d8b;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/page-filter/page-filter.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/page-filter/page-filter.component.ts
new file mode 100644
index 0000000..5a5803b
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/page-filter/page-filter.component.ts
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
+import { MatOption } from '@angular/material/core';
+import { BehaviorSubject, Observable } from 'rxjs';
+import { take, tap } from 'rxjs/operators';
+
+import isEqual from 'lodash.isequal';
+
+import { FilterFormPlaceholders } from './page-filter.config';
+import {
+  DropdownFieldNames,
+  DropdownSelectAllValue,
+  FilterFormControlNames,
+  ImageFilterFormDropdownData,
+  ImageFilterFormValue
+} from '../../images';
+
+@Component({
+  selector: 'datalab-page-filter',
+  templateUrl: './page-filter.component.html',
+  styleUrls: ['./page-filter.component.scss']
+})
+export class PageFilterComponent implements OnInit {
+  @Input() filterDropdownData$: Observable<ImageFilterFormDropdownData>;
+  @Input() filterFormStartValue$: Observable<ImageFilterFormValue>;
+
+  @Output() filterFormValue: EventEmitter<ImageFilterFormValue> = new EventEmitter<ImageFilterFormValue>();
+  @Output() closeFilter: EventEmitter<any> = new EventEmitter<any>();
+  @Output() imageNameValue: EventEmitter<string> = new EventEmitter<string>();
+  @Output() onValueChanges: EventEmitter<string> = new EventEmitter<string>();
+
+  readonly placeholders: typeof FilterFormPlaceholders = FilterFormPlaceholders;
+  readonly dropdownFieldNames: typeof DropdownFieldNames = DropdownFieldNames;
+  readonly controlNames: typeof FilterFormControlNames = FilterFormControlNames;
+  readonly selectAllValue = DropdownSelectAllValue;
+
+  private isApplyBtnDisabled$$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
+  private filterFormStartValue: ImageFilterFormValue;
+
+  filterForm: FormGroup;
+  setFilterValueObservable$: Observable<ImageFilterFormValue>;
+  changeIsApplyBtnDisabledObservable$: Observable<ImageFilterFormValue>;
+  isApplyBtnDisabled$: Observable<boolean> = this.isApplyBtnDisabled$$.asObservable();
+
+  constructor(
+    private fb: FormBuilder
+  ) { }
+
+  ngOnInit(): void {
+    this.createFilterForm();
+    this.onControlChange(this.controlNames.imageName);
+    this.setFilterValue();
+    this.isFilterFormChanged();
+  }
+
+  onSelectClick(): void {
+    const dropdownList = document.querySelectorAll('.cdk-overlay-pane');
+    dropdownList.forEach(el => el.classList.add('normalized-dropdown-position'));
+  }
+
+  confirmFilter(): void {
+    this.filterFormValue.emit(this.filterForm.value);
+  }
+
+  cancelFilter(): void {
+    this.closeFilter.emit();
+  }
+
+  onControlChange(fieldName: keyof ImageFilterFormValue): void {
+    this.filterForm.get(fieldName)?.valueChanges.pipe(
+      tap((inputValue: string) => this.onValueChanges.emit(inputValue))
+    ).subscribe();
+  }
+
+  onClickAll(control: FormControl, allSelected: MatOption, key: DropdownFieldNames ): void {
+    if (allSelected.selected) {
+      this.filterDropdownData$.pipe(
+        tap(value => control.patchValue([...value[key], this.selectAllValue])),
+        take(1)
+      ).subscribe();
+    } else {
+      control.patchValue([]);
+    }
+  }
+
+  private createFilterForm(): void {
+    this.filterForm = this.fb.group({
+      imageName: '',
+      endpoints: [[]],
+      statuses: [[]],
+      templateNames: [[]],
+      sharingStatuses: [[]],
+    });
+  }
+
+  private setFilterValue(): void {
+    this.setFilterValueObservable$ = this.filterFormStartValue$.pipe(
+      tap(value => this.updateFilterForm(value))
+      );
+  }
+
+  private updateFilterForm(value: ImageFilterFormValue): void {
+    this.filterFormStartValue = value;
+    this.filterForm.patchValue(value);
+  }
+
+  private isFilterFormChanged(): void {
+    this.changeIsApplyBtnDisabledObservable$ = this.filterForm.valueChanges.pipe(
+      tap(formValue => this.isApplyBtnDisabled$$.next(isEqual(formValue, this.filterFormStartValue)))
+    );
+  }
+
+  get statuses() {
+    return this.filterForm.get(DropdownFieldNames.statuses) as FormControl;
+  }
+
+  get endpoints() {
+    return this.filterForm.get(DropdownFieldNames.endpoints) as FormControl;
+  }
+
+  get templateNames() {
+    return this.filterForm.get(DropdownFieldNames.templateNames) as FormControl;
+  }
+
+  get sharingStatuses() {
+    return this.filterForm.get(DropdownFieldNames.sharingStatuses) as FormControl;
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/page-filter/page-filter.config.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/page-filter/page-filter.config.ts
new file mode 100644
index 0000000..871550a
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/page-filter/page-filter.config.ts
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export enum FilterFormPlaceholders {
+  imageName = 'Search in images\' names',
+  status = 'Select status',
+  endpoint = 'Select endpoint',
+  templateName = 'Select template name',
+  sharing = 'Select sharing status'
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.html
new file mode 100644
index 0000000..35559f7
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.html
@@ -0,0 +1,353 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<section class="image-list--wrapper">
+  <nav class="image-list__nav-bar">
+    <div class="selection">
+      <div class="mat-reset">
+        <div class="control selector-wrapper"
+             [ngClass]="{'disabled-select': !isProjectsMoreThanOne}"
+        >
+          <mat-form-field>
+            <mat-label>{{placeholder.projectSelect}}</mat-label>
+
+            <mat-select
+              disableOptionCentering
+              name="project"
+              [(value)]="activeProjectName"
+              panelClass="top-select scrolling"
+              [disabled]="!isProjectsMoreThanOne"
+            >
+              <mat-option
+                *ngIf="isProjectsMoreThanOne"
+                (click)="onSelectClick()"
+              >
+                Show all
+              </mat-option>
+              <mat-option
+                *ngFor="let project of projectList"
+                [value]="project"
+                (click)="onSelectClick(project)"
+              >
+                {{ project }}
+              </mat-option>
+              <mat-option *ngIf="!projectList?.length" class="multiple-select ml-10" disabled>
+                Projects list is empty
+              </mat-option>
+            </mat-select>
+            <button class="caret" [disabled]="!isProjectsMoreThanOne">
+              <i class="material-icons">keyboard_arrow_down</i>
+            </button>
+          </mat-form-field>
+        </div>
+      </div>
+    </div>
+
+    <div class="button--wrapper">
+
+
+<!--      <span class="action-button&#45;&#45;wrapper">-->
+<!--          <button-->
+<!--            type="button"-->
+<!--            class="butt action-button"-->
+<!--            mat-raised-button-->
+<!--            [disabled]="!isImageSelected"-->
+<!--            (click)="onActionClick()"-->
+<!--          >-->
+<!--            Actions-->
+<!--            <i class="material-icons" >{{ !isActionsOpen ?  'expand_more' : 'expand_less' }}</i>-->
+<!--          </button>-->
+<!--        <div class="action-menu" *ngIf="isActionsOpen">-->
+<!--          <button-->
+<!--            type="button"-->
+<!--            class="butt action-menu-item"-->
+<!--            mat-raised-button-->
+<!--            [disabled]="true"-->
+<!--          >-->
+<!--            Terminate-->
+<!--          </button>-->
+
+<!--          <button-->
+<!--            type="button"-->
+<!--            class="butt action-menu-item"-->
+<!--            mat-raised-button-->
+<!--            [disabled]="true"-->
+<!--          >-->
+<!--            Share-->
+<!--          </button>-->
+<!--        </div>-->
+<!--      </span>-->
+      <div
+        class="filter__wrapper"
+        datalabClickedOutsideMatSelect
+        (clickedOutside)="onClickOutside()"
+        [isFormOpened]="isFilterOpened | async"
+      >
+        <button mat-raised-button [disabled]="!(dataSource | async)?.length && !($isFiltered | async)" class="butt filter__btn" (click)="onFilterClick()">
+          <i class="material-icons" [ngClass]="{'filtered-icon': $isFiltered | async}">filter_list</i>
+          <span class="filter__btn--name" [ngClass]="{'filtered-icon': $isFiltered | async}">Filter</span>
+          <button *ngIf="$isFiltered | async" type="button" (click)="onResetFilterClick($event)" class="close__btn">&times;</button>
+        </button>
+
+        <div *ngIf="isFilterOpened | async" class="filer__component--wrapper">
+          <datalab-page-filter
+            [filterDropdownData$]="$filterDropdownData"
+            [filterFormStartValue$]="$filterFormValue"
+            (filterFormValue)="onFilterApplyClick($event)"
+            (closeFilter)="onFilterCancelClick()"
+            (onValueChanges)="onControlChanges(dropdownFieldNames.imageNames, $event)"
+          >
+          </datalab-page-filter>
+        </div>
+      </div>
+
+      <button
+        mat-raised-button
+        class="butt mr-10 show-active__btn"
+        (click)="toggleShowActive()"
+      >
+        <span *ngIf="isShowActive; else inactive">
+          <i class="material-icons">visibility_off</i> Show active
+        </span>
+        <ng-template #inactive>
+          <span>
+            <i class="material-icons">visibility</i> Show all
+          </span>
+        </ng-template>
+      </button>
+
+      <span>
+        <button mat-raised-button class="butt" (click)="onRefreshClick()">
+          <i class="material-icons highlight">autorenew</i>
+          Refresh
+        </button>
+      </span>
+    </div>
+  </nav>
+
+  <mat-divider></mat-divider>
+
+    <table
+      mat-table
+      [dataSource]="projectSource | async"
+      multiTemplateDataRows
+      class="data-grid resources mat-elevation-z6"
+      [trackBy]="trackBy"
+    >
+
+      <ng-container matColumnDef="project">
+        <td mat-cell *matCellDef="let element" [attr.colspan]="8" class="image-page__project">
+          {{ element?.project }}
+        </td>
+      </ng-container>
+
+      <ng-container matColumnDef="checkbox">
+        <th mat-header-cell *matHeaderCellDef class="image-checkbox--wrapper">
+          <div class="header-cell--wrapper">
+<!--          <span  *ngIf="(dataSource | async)?.length" >-->
+<!--            <datalab-checkbox-->
+<!--              (click)="allCheckboxToggle()"-->
+<!--              [checked]="checkboxSelected"-->
+<!--              class="image-checkbox"-->
+<!--            ></datalab-checkbox>-->
+<!--          </span>-->
+          </div>
+        </th>
+      </ng-container>
+
+      <ng-container matColumnDef="imageName">
+        <th mat-header-cell *matHeaderCellDef class="name-col header-cell">
+          <span class="label image-label" [ngClass]="{'filtered-icon': ($filteredColumnState | async)?.imageName}">
+            {{tableHeaderCellTitles.imageName}}
+            <button
+              *ngIf="($filteredColumnState | async)?.imageName"
+              type="button"
+              class="close__btn header__close--btn"
+              (click)="onResetColumn(columnFieldNames.imageName)"
+            >
+              &times;
+            </button>
+          </span>
+        </th>
+      </ng-container>
+
+      <ng-container matColumnDef="imageStatus">
+        <th mat-header-cell *matHeaderCellDef class="status-col header-cell">
+          <span class="label image-label" [ngClass]="{'filtered-icon': ($filteredColumnState | async)?.statuses}">
+            {{tableHeaderCellTitles.imageStatus}}
+            <button
+              *ngIf="($filteredColumnState | async)?.statuses"
+              type="button"
+              class="close__btn header__close--btn"
+              (click)="onResetColumn(columnFieldNames.statuses)"
+            >
+              &times;
+            </button>
+          </span>
+        </th>
+      </ng-container>
+
+      <ng-container matColumnDef="creationDate">
+        <th mat-header-cell *matHeaderCellDef class="shape-col header-cell">
+          <span class="label image-label"> {{tableHeaderCellTitles.creationDate}} </span>
+        </th>
+      </ng-container>
+
+      <ng-container matColumnDef="endpoint">
+        <th mat-header-cell *matHeaderCellDef class="tag-col header-cell">
+          <span class="label image-label" [ngClass]="{'filtered-icon': ($filteredColumnState | async)?.endpoints}">
+            {{tableHeaderCellTitles.endpoint}}
+            <button
+              *ngIf="($filteredColumnState | async)?.endpoints"
+              type="button"
+              class="close__btn header__close--btn"
+              (click)="onResetColumn(columnFieldNames.endpoints)"
+            >
+              &times;
+            </button>
+          </span>
+        </th>
+      </ng-container>
+
+      <ng-container matColumnDef="templateName">
+        <th mat-header-cell *matHeaderCellDef class="resources-col label-header">
+          <span class="label image-label" [ngClass]="{'filtered-icon': ($filteredColumnState | async)?.templateNames}">
+            {{tableHeaderCellTitles.templateName}}
+            <button
+              *ngIf="($filteredColumnState | async)?.templateNames"
+              type="button"
+              class="close__btn header__close--btn"
+              (click)="onResetColumn(columnFieldNames.templateNames)"
+            >
+              &times;
+            </button>
+          </span>
+        </th>
+      </ng-container>
+
+      <ng-container matColumnDef="sharedStatus">
+        <th mat-header-cell *matHeaderCellDef class="cost-col label-header">
+          <span class="label image-label" [ngClass]="{'filtered-icon': ($filteredColumnState | async)?.sharingStatuses}">
+            {{tableHeaderCellTitles.sharedStatus}}
+            <button
+              *ngIf="($filteredColumnState | async)?.sharingStatuses"
+              type="button"
+              class="close__btn header__close--btn"
+              (click)="onResetColumn(columnFieldNames.sharingStatuses)"
+            >
+              &times;
+            </button>
+          </span>
+        </th>
+      </ng-container>
+
+      <ng-container matColumnDef="actions">
+        <th mat-header-cell *matHeaderCellDef class="settings label-header">
+          <span class="label image-label"> {{tableHeaderCellTitles.actions}} </span>
+        </th>
+      </ng-container>
+
+      <!-- -------------------------TABLE BODY---------------------------- -->
+
+      <ng-container matColumnDef="expandedDetail">
+        <td mat-cell *matCellDef="let element" class="exploratory" [attr.colspan]="8">
+          <tr *ngFor="let element of element?.images; let i = index" class="element-row mat-row">
+            <td mat-cell class="image-checkbox--wrapper">
+<!--              <datalab-checkbox-->
+<!--                (click)="onCheckboxClick(element)"-->
+<!--                class="image-checkbox"-->
+<!--                [checked]="element.isSelected"-->
+<!--              ></datalab-checkbox>-->
+            </td>
+
+            <td class="name-col image-table-cell">
+              <span>
+                {{ element.name }}
+              </span>
+            </td>
+            <td class="status-col status image-table-cell" ngClass="{{ element.status.toLowerCase() || ''}}">
+              {{element.status | titlecase}}
+            </td>
+            <td class="shape-col image-table-cell">
+              <span> {{element.timestamp | localDate : 'short'}} </span>
+            </td>
+
+            <td class="tag-col selection image-table-cell">
+              {{element.endpoint }}
+            </td>
+
+            <td class="resources-col image-table-cell">
+              {{element.templateName }}
+            </td>
+            <td class="cost-col image-table-cell">
+              <div class="shared-status--wrapper">
+                <span class="shared-status"> {{element.sharingStatus | titlecase}} </span>
+              </div>
+            </td>
+
+            <td mat-cell class="settings actions-col">
+              <div class="button--wrapper action__button--wrapper">
+                <span class="currency_details" (click)="onImageInfoClick(element)">
+                  <i class="material-icons">help_outline</i>
+                </span>
+                <span
+                  *ngIf="element.imageUserPermissions | isElementAvailable: isObjectFieldTrue"
+                  class="actions"
+                  #settings
+                  (click)="actions.toggle($event, settings)"
+                ></span>
+              </div>
+              <bubble-up #actions class="list-menu" position="bottom-left" alternative="top-left">
+                <ul class="list-unstyled">
+                  <li *ngIf="element.imageUserPermissions.canShare">
+                    <button
+                      class="action-button__share"
+                      (click)="onActionClick(element, imageActionType.share)"
+                    >
+                      <i class="material-icons">screen_share</i>
+                      <span>Share</span>
+                    </button>
+                  </li>
+                  <li *ngIf="element.imageUserPermissions.canTerminate"
+                      (click)="onActionClick(element, imageActionType.terminate)">
+                    <button class="action-button__share">
+                      <i class="material-icons">phonelink_off</i>
+                      <span>Terminate</span>
+                    </button>
+                  </li>
+                </ul>
+              </bubble-up>
+            </td>
+          </tr>
+        </td>
+      </ng-container>
+
+      <ng-container matColumnDef="placeholder">
+        <td mat-footer-cell *matFooterCellDef class="info" [colSpan]="displayedColumns.length - 1">
+          <span>{{ ($isFiltered | async) ? 'No matches found' : 'There are no images yet' }}</span>
+        </td>
+      </ng-container>
+
+      <tr mat-header-row *matHeaderRowDef="displayedColumns;" class="header-row"></tr>
+
+      <tr mat-row [hidden]="!element?.images.length" *matRowDef="let element; columns: ['project']" class="element-row"></tr>
+      <tr mat-row [hidden]="!row?.images.length" *matRowDef="let row; columns: ['expandedDetail']" class="detail-row"></tr>
+      <tr [hidden]="!($isProjectListEmpty | async)" mat-footer-row *matFooterRowDef="['placeholder']"></tr>
+    </table>
+</section>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.scss
new file mode 100644
index 0000000..a0587b7
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.scss
@@ -0,0 +1,261 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+.image-list {
+  &--wrapper {
+    padding: 12px 15px;
+  }
+
+  &__nav-bar {
+    display: flex;
+    justify-content: space-between;
+  }
+}
+
+.action-button {
+  padding: 0 38px 0 45px;
+
+  &--wrapper {
+    position: relative;
+    margin-right: 10px;
+  }
+}
+
+.image-table {
+  width: 100%;
+}
+
+.image-checkbox {
+  &--wrapper {
+    padding-left: 10px !important;
+  }
+}
+
+.currency_details {
+  display: flex;
+  color: #35afd5;
+  cursor: pointer;
+  transition: all 0.45s ease-in-out;
+}
+
+.material-icons {
+  font-size: 18px;
+}
+
+.button--wrapper,
+.header-cell--wrapper {
+  position: relative;
+  display: flex;
+  justify-content: space-between;
+}
+
+.shared-status {
+  padding-right: 16px;
+
+  &--wrapper {
+    display: flex;
+  }
+}
+
+.date-item {
+  margin-right: 10px;
+}
+
+.action-menu {
+  position: absolute;
+  z-index: 10;
+}
+
+.action-menu-item:disabled {
+  color: rgba(180, 179, 179, 0.87) !important;
+  background-color: white;
+  opacity: 1;
+}
+
+.action-button__share {
+  display: flex;
+  align-items: flex-start;
+  width: 100%;
+  padding: 10px 15px;
+  background-color: transparent;
+  color: rgb(87, 114, 137);
+  border: none;
+  outline: none;
+
+  &:hover {
+    color: #35afd5;
+    cursor: pointer;
+  }
+
+  &:disabled {
+    background-color: rgba(0, 0, 0, 0.12);
+    color: rgba(0, 0, 0, 0.26);
+    cursor: not-allowed;
+    transition: all 0.45s ease-in-out;
+  }
+}
+
+.list-menu {
+  padding: 0 !important;
+}
+
+.list-unstyled > li {
+  margin: 0 !important;
+}
+
+.filer__component--wrapper {
+  position: absolute;
+  top: 46px;
+  //UNCOMMENT AFTER UNCOMMENT ACTION MENU
+  //left: 135px;
+  left: -35px;
+  z-index: 10;
+}
+
+.filter__btn {
+  position: relative;
+  margin-right: 10px;
+  vertical-align: middle;
+  width: 110px;
+
+  &--name {
+    line-height: 0;
+  }
+}
+
+.show-active__btn {
+  line-height: 1;
+}
+
+.close__btn {
+  position: absolute;
+  top: 0px;
+  right: 2px;
+  width: 12px;
+  color: rgb(87, 114, 137);
+  background-color: transparent;
+  font-size: 15px;
+  border: none;
+  outline: none;
+
+  &:hover {
+    color: #35afd5;
+    cursor: pointer;
+  }
+}
+
+.image-page__project {
+  font-weight: 600;
+  color: #577289;
+  padding-left: 21px;
+}
+
+.image-checkbox--wrapper {
+    width: 4%;
+}
+
+table.resources .header-row > .header-cell {
+  padding: 5px 0;
+}
+
+table.resources .exploratory .element-row td.actions-col {
+  padding: 0;
+}
+
+table.resources .exploratory .element-row td,
+table.resources .header-row > .header-cell,
+table.resources .header-row th.label-header,{
+  padding: 0;
+}
+
+table.resources .header-row .label.image-label {
+  padding-top: 0px;
+  vertical-align: inherit !important;
+}
+
+.image-table-cell {
+  padding: 0 !important;
+}
+
+table.resources {
+  & .name-col.header-cell {
+    width: 15.5%;
+  }
+
+  & .shape-col.image-table-cell,
+  & .tag-col.image-table-cell {
+    width: 17%;
+  }
+
+  & .shape-col.header-cell,
+  & .tag-col.header-cell{
+    width: 15.7%;
+  }
+
+  & .resources-col.image-table-cell {
+    width: 23%;
+  }
+
+  & .resources-col.label-header {
+    width: 21%;
+  }
+
+  & .settings.actions-col,
+  & .settings.label-header {
+    width: 7%;
+  }
+
+  &  .status-col.header-cell {
+    width: 10.1%;
+  }
+
+  & .cost-col.label-header {
+    width: 12.5%;
+  }
+}
+
+.settings.image-table-cell,
+.settings.label-header {
+  width: 12%;
+}
+
+.action__button--wrapper {
+  width: 100%;
+}
+
+table.resources .label-header.settings {
+  padding-right: 15px !important;
+}
+
+td.mat-cell.image-page__project {
+  padding-left: 3.75%;
+}
+
+.filtered-icon {
+  color: #35afd5;
+}
+
+.label {
+  position: relative;
+}
+
+.header__close--btn.close__btn {
+  top: -15px;
+  right: -15px;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.ts
new file mode 100644
index 0000000..a030162
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.component.ts
@@ -0,0 +1,321 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Component, OnDestroy, OnInit } from '@angular/core';
+import { MatDialog } from '@angular/material/dialog';
+import { EMPTY, Observable, of } from 'rxjs';
+import { catchError, map, switchMap, tap } from 'rxjs/operators';
+
+import { ComponentType, ToastrService } from 'ngx-toastr';
+
+import { GeneralEnvironmentStatus } from '../../administration/management/management.model';
+import { ApplicationSecurityService, HealthStatusService } from '../../core/services';
+import {
+  FilteredColumnList,
+  ImageActionType,
+  ImageFilterFormDropdownData,
+  ImageFilterFormValue,
+  ImageModel,
+  ImageParams,
+  ProjectModel
+} from './images.model';
+import {
+  Image_Table_Column_Headers,
+  Image_Table_Titles,
+  ImageStatuses,
+  Localstorage_Key,
+  Placeholders,
+  SharingStatus,
+  DropdownFieldNames,
+  FilterFormInitialValue,
+  ImageModelKeysForFilter,
+  DropdownSelectAllValue,
+  FilterFormControlNames,
+  ImageActions,
+  Toaster_Message,
+} from './images.config';
+import { ImagesService } from './images.service';
+import { ProgressBarService } from '../../core/services/progress-bar.service';
+import { ImageDetailDialogComponent } from '../exploratory/image-detail-dialog/image-detail-dialog.component';
+import { ActivatedRoute } from '@angular/router';
+import { ShareDialogComponent } from '../exploratory/image-action-dialog/share-dialog/share-dialog.component';
+import { TerminateDialogComponent } from '../exploratory/image-action-dialog/terminate-dialog/terminate-dialog.component';
+
+@Component({
+  selector: 'datalab-images',
+  templateUrl: './images.component.html',
+  styleUrls: [
+    './images.component.scss',
+    '../resources-grid/resources-grid.component.scss',
+    '../resources.component.scss'
+  ]
+})
+
+export class ImagesComponent implements OnInit, OnDestroy {
+  readonly tableHeaderCellTitles: typeof Image_Table_Column_Headers = Image_Table_Column_Headers;
+  readonly displayedColumns: typeof Image_Table_Titles = Image_Table_Titles;
+  readonly placeholder: typeof Placeholders = Placeholders;
+  readonly sharedStatus: typeof SharingStatus = SharingStatus;
+  readonly imageStatus: typeof ImageStatuses = ImageStatuses;
+  readonly columnFieldNames: typeof FilterFormControlNames = FilterFormControlNames;
+  readonly dropdownFieldNames: typeof DropdownFieldNames = DropdownFieldNames;
+  readonly imageActionType: typeof ImageActions = ImageActions;
+
+  isActionsOpen: boolean = false;
+  dataSource: Observable<ImageModel[]>;
+  projectSource: Observable<ProjectModel[]>;
+  checkboxSelected: boolean = false;
+  projectList: string[] = [];
+  activeProjectName: string = '';
+  userName: string;
+  isProjectsMoreThanOne: boolean;
+  isFilterOpened: Observable<boolean>;
+  $filterDropdownData: Observable<ImageFilterFormDropdownData>;
+  $filterFormValue: Observable<ImageFilterFormValue>;
+  $isProjectListEmpty: Observable<boolean>;
+  $filteredColumnState: Observable<FilteredColumnList>;
+  $isFiltered: Observable<boolean>;
+  isShowActive: boolean = true;
+
+  constructor(
+    private healthStatusService: HealthStatusService,
+    public toastr: ToastrService,
+    private dialog: MatDialog,
+    private imagesService: ImagesService,
+    private progressBarService: ProgressBarService,
+    private route: ActivatedRoute,
+    private applicationSecurityService: ApplicationSecurityService
+  ) { }
+
+  ngOnInit(): void {
+    this.getEnvironmentHealthStatus();
+    this.getUserImagePageInfo();
+    this.getUserName();
+    this.initImageTable();
+    this.initFilterBtn();
+    this.getDropdownList();
+    this.getFilterFormValue();
+    this.getIsProjectListEmpty();
+    this.initFilteredColumnState();
+    this.initIsImageListFiltered();
+  }
+
+  ngOnDestroy(): void {
+    this.imagesService.closeFilter();
+    this.imagesService.setFilterFormValue(FilterFormInitialValue);
+  }
+
+  trackBy(index, item) {
+    return null;
+  }
+
+  onCheckboxClick(element: ImageModel): void {
+    element.isSelected = !element.isSelected;
+  }
+
+  allCheckboxToggle(): void {
+    this.checkboxSelected = !this.checkboxSelected;
+    this.imagesService.changeCheckboxValue(this.checkboxSelected);
+  }
+
+  onActionBtnClick(): void {
+    this.isActionsOpen = !this.isActionsOpen;
+  }
+
+  isObjectFieldTrue(elementField: ImageModel): boolean {
+    return (<any>Object).values(elementField).some(item => Boolean(item));
+  }
+
+  onSelectClick(projectName: string = ''): void {
+    this.imagesService.getActiveProject(projectName);
+    this.activeProjectName = projectName;
+  }
+
+  onRefreshClick(): void {
+    this.imagesService.getImagePageInfo().subscribe();
+    this.activeProjectName = '';
+  }
+
+  onImageInfoClick(image: ImageModel): void {
+    this.dialog.open(ImageDetailDialogComponent, {
+      data: {
+        image
+      },
+      panelClass: 'modal-md'
+    });
+  }
+
+  onActionClick(image: ImageModel, actionType: ImageActionType): void {
+    let imageInfo: ImageParams;
+    const data = this.imagesService.createActionDialogConfig(image, actionType);
+    const requestCallback = this.imagesService.getRequestByAction(actionType).bind(this.imagesService);
+    const component = this.getComponentByAction(actionType);
+
+    this.dialog.open(component, {
+      data,
+      panelClass: 'modal-sm'
+    }).afterClosed()
+      .pipe(
+        tap(userDataList => {
+          imageInfo = this.imagesService.createImageRequestInfo(image, userDataList);
+        }),
+        switchMap((confirm) => {
+          if (confirm) {
+            return requestCallback(imageInfo, actionType);
+          }
+          return EMPTY;
+        }),
+        tap(() => this.callActionHelpers(actionType, this.callToasterShareSuccess)),
+        catchError(() => of(this.callToasterShareError(actionType)))
+    )
+      .subscribe();
+  }
+
+  onFilterClick(): void {
+    this.imagesService.openFilter();
+  }
+
+  onFilterApplyClick(filterFormValue: ImageFilterFormValue): void {
+    const normalizeFilterFormValue = this.imagesService.normalizeFilterFormValue(filterFormValue, DropdownSelectAllValue);
+    this.imagesService.updateFilterColumnState(normalizeFilterFormValue);
+    this.imagesService.filterImagePageInfo(normalizeFilterFormValue).subscribe();
+    this.imagesService.setFilterFormValue(filterFormValue);
+    this.imagesService.checkIsPageFiltered();
+    this.imagesService.closeFilter();
+  }
+
+  onFilterCancelClick(): void {
+    this.imagesService.closeFilter();
+  }
+
+  onControlChanges(controlName: keyof ImageFilterFormDropdownData, inputValue: string): void {
+    const normalizedInputValue = inputValue.toLowerCase();
+    this.imagesService.filterDropdownField(DropdownFieldNames.imageNames, normalizedInputValue);
+  }
+
+  toggleShowActive(): void {
+    this.isShowActive = !this.isShowActive;
+    this.imagesService.showImage(this.isShowActive, ImageModelKeysForFilter.status, ImageStatuses.active);
+  }
+
+  onResetFilterClick(event: Event): void {
+    event.stopPropagation();
+    this.imagesService.filterImagePageInfo(FilterFormInitialValue).subscribe();
+    this.imagesService.setFilterFormValue(FilterFormInitialValue);
+    this.imagesService.updateFilterColumnState(FilterFormInitialValue);
+    this.imagesService.checkIsPageFiltered();
+  }
+
+  onResetColumn(dropdownFieldNames: FilterFormControlNames): void {
+    this.imagesService.resetFilterField(dropdownFieldNames, DropdownSelectAllValue);
+  }
+
+  onClickOutside(): void {
+    this.imagesService.closeFilter();
+  }
+
+  private getComponentByAction(actionType): ComponentType<unknown> {
+    const componentList = {
+      share: ShareDialogComponent,
+      terminate: TerminateDialogComponent
+    };
+    return componentList[actionType];
+  }
+
+  private callActionHelpers(actionType: ImageActionType, callback?: (actionType: string) => void): void {
+    const toasterInvoke = callback.bind(this);
+    toasterInvoke(actionType);
+    this.checkAuthorize();
+    this.progressBarService.stopProgressBar();
+  }
+
+  private callToasterShareSuccess(actionType: ImageActionType): void {
+    if (actionType === ImageActions.share) {
+      this.toastr.success(Toaster_Message.successShare, 'Success!');
+    }
+  }
+
+  private callToasterShareError(actionType: ImageActionType): void {
+    if (actionType === ImageActions.share) {
+      this.toastr.error('Something went wrong. Please try again.', 'Oops!');
+    }
+  }
+
+  private checkAuthorize(): void {
+    this.applicationSecurityService.isLoggedIn().subscribe(() => {
+      this.getEnvironmentHealthStatus();
+    });
+  }
+
+  private getEnvironmentHealthStatus(): void {
+    this.healthStatusService.getEnvironmentHealthStatus().subscribe();
+  }
+
+  private initFilteredColumnState(): void {
+    this.$filteredColumnState = this.imagesService.filteredColumnState$;
+  }
+
+  private getUserImagePageInfo(): void {
+    this.route.data.pipe(
+      map(data => data['projectList']),
+      tap((response) => this.imagesService.initImagePageInfo(response)),
+      tap(({projectImagesInfos}) => this.getProjectList(projectImagesInfos)),
+    ).subscribe();
+  }
+
+  private initImageTable(): void {
+    this.dataSource = this.imagesService.imageList$;
+    this.projectSource = this.imagesService.projectList$;
+  }
+
+  private getProjectList(imagePageList: ProjectModel[]): void {
+    if (!imagePageList) {
+      return;
+    }
+    this.projectList = this.imagesService.getProjectNameList(imagePageList);
+    this.isProjectsMoreThanOne = this.projectList.length > 1;
+    if (!this.isProjectsMoreThanOne) {
+      this.activeProjectName = this.projectList[0];
+    }
+  }
+
+  private getUserName(): void {
+    this.userName = localStorage.getItem(Localstorage_Key.userName);
+  }
+
+  private initFilterBtn(): void {
+    this.isFilterOpened = this.imagesService.isFilterOpened$;
+  }
+
+  private getDropdownList(): void {
+    this.$filterDropdownData = this.imagesService.filterDropdownData$;
+  }
+
+  private getFilterFormValue(): void {
+    this.$filterFormValue = this.imagesService.filterFormValue$;
+  }
+
+  private getIsProjectListEmpty(): void {
+    this.$isProjectListEmpty = this.imagesService.isProjectListEmpty$;
+  }
+
+  private initIsImageListFiltered(): void {
+    this.$isFiltered = this.imagesService.isImageListFiltered$;
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.config.ts b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.config.ts
new file mode 100644
index 0000000..247f47d
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.config.ts
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export enum Image_Table_Column_Headers {
+  imageName = 'Image name',
+  creationDate = 'Creation date',
+  provider = 'Provider',
+  imageStatus = 'Status',
+  sharedStatus = 'Shared status',
+  templateName = 'Template name',
+  actions = 'Actions',
+  endpoint = 'Endpoint',
+}
+
+export enum SharingStatus {
+  shared = 'SHARED',
+  private = 'PRIVATE',
+  received = 'RECEIVED'
+}
+
+export const Image_Table_Titles = <const>[
+  'checkbox',
+  'imageName',
+  'imageStatus',
+  'creationDate',
+  'endpoint',
+  'templateName',
+  'sharedStatus',
+  'actions'
+];
+
+export enum Localstorage_Key {
+  userName = 'user_name'
+}
+
+export enum Toaster_Message {
+  successTitle = 'Success!',
+  successShare = 'The image has been successfully shared.',
+  successTerminate = 'The image has been terminated',
+  successUnShare = 'The action has been performed successfully.'
+}
+
+export enum Placeholders {
+  projectSelect = 'Select project'
+}
+
+export enum ImageStatuses {
+  creating = 'CREATING',
+  active = 'ACTIVE',
+  failed = 'FAILED'
+}
+
+export enum TooltipStatuses {
+  activeOnly = 'The image cannot be shared because it is not in the "Active" status',
+  creatorOnly = 'Images may be shared by creators only',
+  unableTerminate = 'Unable to terminate notebook because at least one compute is in progress'
+}
+
+export enum DropdownFieldNames {
+  imageNames = 'imageNames',
+  endpoints = 'endpoints',
+  templateNames = 'templateNames',
+  statuses = 'statuses',
+  sharingStatuses = 'sharingStatuses'
+}
+
+export enum FilterFormControlNames {
+  imageName = 'imageName',
+  endpoints = 'endpoints',
+  templateNames = 'templateNames',
+  statuses = 'statuses',
+  sharingStatuses = 'sharingStatuses'
+}
+
+export const FilterFormInitialValue = {
+    endpoints: [],
+    imageName: '',
+    statuses: [],
+    templateNames: [],
+    sharingStatuses: [],
+};
+
+export const ChangedColumnStartValue = {
+    endpoints: false,
+    imageNames: false,
+    statuses: false,
+    templateNames: false,
+    sharingStatuses: false,
+};
+
+export enum ImageModelKeysForFilter {
+  status = 'status',
+  name = 'name',
+  endpoint = 'endpoint',
+  templateName = 'templateName',
+  shared = 'shared'
+}
+
+export const DropdownSelectAllValue = 'selectAllFound';
+
+export enum ImageActions {
+  share = 'share',
+  terminate = 'terminate'
+}
+
+export enum ModalTitle {
+  share = 'Share image',
+  terminate = 'Terminate image',
+  unShare = '! Warning',
+  addPlatform = 'Add platform'
+}
+
+export enum URL_Chunk {
+  sharingInfo = 'sharing_info',
+  autocomplete = 'share_autocomplete'
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.model.ts b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.model.ts
new file mode 100644
index 0000000..0377132
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.model.ts
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { UserData } from '../exploratory/image-action-dialog/image-action.model';
+import { ModalTitle } from './images.config';
+
+export interface ProjectImagesInfo {
+  filterData: ImageFilterFormDropdownData;
+  imageFilter: ImageFilterFormValue;
+  projectImagesInfos: ProjectModel[];
+}
+
+export interface ProjectModel {
+  project: string;
+  images: ImageModel[];
+}
+
+export interface ImageModel {
+  application: string;
+  cloudProvider: 'AWS' | 'GCP' | 'Azure';
+  timestamp: string;
+  description: string;
+  endpoint: string;
+  fullName: string;
+  instanceName: string;
+  imageUserPermissions: ImageUserPermissions;
+  name: string;
+  project: string;
+  sharedWith: SharedWithField;
+  sharingStatus: 'SHARED'| 'PRIVATE' | 'RECEIVED';
+  status: 'ACTIVE' | 'CREATING' | 'FAILED';
+  user: string;
+  isSelected?: boolean;
+  libraries: Library[];
+  computationalLibraries: Library[];
+  clusterConfig: ClusterConfig;
+  templateName: string;
+}
+
+export interface ImageUserPermissions {
+  canShare: boolean;
+  canTerminate: boolean;
+}
+
+export interface ImageParams {
+  imageName: string;
+  projectName: string;
+  endpoint: string;
+  sharedWith?: UserData[];
+}
+
+export interface ImageActionModalData {
+  actionType: ImageActionType;
+  title: string;
+  image: ImageModel;
+  isShared?: boolean;
+}
+
+export interface ImageDetailModalData {
+  image: ImageModel;
+}
+
+export type ImageActionType = 'share' | 'terminate';
+
+export interface Library {
+  add_pkgs: string[];
+  available_versions: string[];
+  error_message: string;
+  group: string;
+  name: string;
+  status: string;
+  version: string;
+  resourceName: string;
+  type: 'EXPLORATORY';
+}
+
+export interface ClusterConfig {
+  Classification: string;
+  Properties: Record<string, any>;
+  Configurations: any[];
+}
+
+export interface ImageFilterFormDropdownData {
+  imageNames: string[];
+  statuses: string[];
+  endpoints: string[];
+  templateNames: string[];
+  sharingStatuses: string[];
+}
+
+export interface ImageFilterFormValue {
+  endpoints: string[];
+  imageName: string;
+  statuses: string[];
+  templateNames: string[];
+  sharingStatuses: string[];
+}
+
+
+export interface LibraryInfoItem {
+  name: string;
+  libs: string[];
+}
+
+export interface FilteredColumnList {
+  imageNames: boolean;
+  statuses: boolean;
+  endpoints: boolean;
+  templateNames: boolean;
+  sharingStatuses: boolean;
+}
+
+export type FilterFormItemType = [string, string[] | string];
+
+export interface UnShareModal {
+  userData: UserData;
+  title: ModalTitle;
+}
+
+export interface SharedWithField {
+  users: string[];
+  groups: string[];
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/images/images.service.ts b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.service.ts
new file mode 100644
index 0000000..284da13
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/images/images.service.ts
@@ -0,0 +1,305 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Injectable } from '@angular/core';
+import { take, tap } from 'rxjs/operators';
+import { BehaviorSubject, Observable } from 'rxjs';
+
+import {
+  FilteredColumnList,
+  FilterFormItemType,
+  ImageFilterFormDropdownData,
+  ImageFilterFormValue,
+  ImageModel,
+  ProjectImagesInfo,
+  ProjectModel,
+  ImageParams,
+  ImageActionType,
+  ImageActionModalData
+} from './images.model';
+import { ApplicationServiceFacade, ImagesPageService } from '../../core/services';
+import { ChangedColumnStartValue, FilterFormInitialValue, ModalTitle, SharingStatus } from './images.config';
+import { ShareDialogData, UserData } from '../exploratory/image-action-dialog/image-action.model';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class ImagesService {
+  private projectList$$: BehaviorSubject<ProjectModel[]> = new BehaviorSubject<ProjectModel[]>([]);
+  private isProjectListEmpty$$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
+  private cashedProjectList$$: BehaviorSubject<ProjectModel[]> = new BehaviorSubject<ProjectModel[]>([]);
+  private imageList$$: BehaviorSubject<ImageModel[]> = new BehaviorSubject<ImageModel[]>([]);
+  private isFilterOpened$$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
+  // tslint:disable-next-line:max-line-length
+  private filterDropdownData$$: BehaviorSubject<ImageFilterFormDropdownData> = new BehaviorSubject<ImageFilterFormDropdownData>({} as ImageFilterFormDropdownData);
+  private filterFormValue$$: BehaviorSubject<ImageFilterFormValue> = new BehaviorSubject<ImageFilterFormValue>(FilterFormInitialValue);
+  private filteredColumnState$$: BehaviorSubject<FilteredColumnList> = new BehaviorSubject<FilteredColumnList>(ChangedColumnStartValue);
+  private isImageListFiltered$$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
+  private dropdownStartValue: ImageFilterFormDropdownData;
+
+  projectList$ = this.projectList$$.asObservable();
+  isProjectListEmpty$ = this.isProjectListEmpty$$.asObservable();
+  imageList$ = this.imageList$$.asObservable();
+  isFilterOpened$ = this.isFilterOpened$$.asObservable();
+  filterDropdownData$ = this.filterDropdownData$$.asObservable();
+  filterFormValue$ = this.filterFormValue$$.asObservable();
+  filteredColumnState$ = this.filteredColumnState$$.asObservable();
+  isImageListFiltered$ = this.isImageListFiltered$$.asObservable();
+
+  constructor(
+    private applicationServiceFacade: ApplicationServiceFacade,
+    private userImagesPageService: ImagesPageService
+  ) { }
+
+  getImagePageInfo(): Observable<ProjectImagesInfo> {
+    return this.userImagesPageService.getFilterImagePage()
+      .pipe(
+        tap(imagePageInfo => this.initImagePageInfo(imagePageInfo))
+      );
+  }
+
+  filterImagePageInfo(params: ImageFilterFormValue): Observable<ProjectImagesInfo> {
+    return this.userImagesPageService.filterImagePage(params)
+      .pipe(
+        tap(value => this.getImagePageData(value.projectImagesInfos)),
+        take(1)
+      );
+  }
+
+  shareImageAllUsers(imageInfo: ImageParams): Observable<ProjectImagesInfo> {
+    return this.userImagesPageService.shareImagesAllUser(imageInfo)
+      .pipe(
+        tap(value => this.getImagePageData(value.projectImagesInfos)),
+        take(1)
+      );
+  }
+
+  terminateImage(imageInfo: ImageParams, action: ImageActionType): Observable<any> {
+    return this.userImagesPageService.terminateImage(imageInfo, action)
+      .pipe(
+        tap(value => this.getImagePageData(JSON.parse(value['body']).projectImagesInfos)),
+        take(1)
+      );
+  }
+
+  getActiveProject(projectName: string): void {
+    const projectList = this.cashedProjectList$$.getValue();
+    if (!projectName) {
+      this.updateProjectList(projectList);
+      this.isProjectListEmpty$$.next(this.isProjectListEmpty(projectList));
+    } else {
+      const currentProject = projectList.find(({project}) => project === projectName);
+      this.updateProjectList([currentProject]);
+      this.isProjectListEmpty$$.next(this.isProjectListEmpty([currentProject]));
+    }
+  }
+
+  getProjectNameList(imageList: ProjectModel[]): string[] {
+    return imageList.map(({project}) => project);
+  }
+
+  updateImageList(imageList: ImageModel[]): void {
+    this.imageList$$.next(imageList);
+  }
+
+  updateProjectList(projectList: ProjectModel[]): void {
+    this.projectList$$.next(projectList);
+  }
+
+  changeCheckboxValue(value: boolean): void {
+    const updatedImageList = this.imageList$$.value.map(image => {
+      image.isSelected = value;
+      return image;
+    });
+    this.imageList$$.next(updatedImageList);
+  }
+
+  openFilter(): void {
+    this.isFilterOpened$$.next(true);
+  }
+
+  closeFilter(): void {
+    this.isFilterOpened$$.next(false);
+  }
+
+  filterDropdownField(field: keyof ImageFilterFormDropdownData, value: string, ): void {
+    const filteredDropdownList = this.dropdownStartValue[field].filter(item => item.toLowerCase().includes(value));
+    this.addFilterDropdownData({...this.filterDropdownData$$.value, imageNames: filteredDropdownList});
+  }
+
+  resetFilterField(field: keyof ImageFilterFormValue, exceptionValue: string = ''): void {
+    const droppedFieldValue = this.getDroppedFieldValue(field);
+    const updatedFilterFormValue = {...this.filterFormValue$$.value, [field]: droppedFieldValue};
+    const normalizeFormValue = this.normalizeFilterFormValue(updatedFilterFormValue, exceptionValue);
+    this.setFilterFormValue(updatedFilterFormValue);
+    this.updateFilterColumnState(normalizeFormValue);
+    this.filterImagePageInfo(normalizeFormValue).subscribe();
+    this.checkIsPageFiltered();
+  }
+
+  setFilterFormValue(value: ImageFilterFormValue): void {
+    this.filterFormValue$$.next(value);
+  }
+
+  showImage(flag: boolean, field: keyof ImageModel, comparedValue: string): void {
+    const projectList = this.cashedProjectList$$.getValue();
+    if (flag) {
+      this.updateProjectList(projectList);
+    } else {
+      const filteredImageList = this.filterByCondition(this.projectList$$.getValue(), field, comparedValue);
+      this.updateProjectList(filteredImageList);
+    }
+  }
+
+  normalizeFilterFormValue(filterFormValue: ImageFilterFormValue, exceptionValue: string = '') {
+    if (!exceptionValue) {
+      return filterFormValue;
+    }
+    return (<any>Object).entries(filterFormValue)
+      .reduce((acc, fieldItem) => this.filterFormValue(acc, fieldItem, exceptionValue), <ImageFilterFormValue>{});
+  }
+
+  updateFilterColumnState(filterFormValue: ImageFilterFormValue): void {
+    const columnStateList = (<any>Object).entries(filterFormValue)
+      .reduce((acc, fieldItem) => this.checkColumnState(acc, fieldItem), <FilteredColumnList>{});
+
+    this.filteredColumnState$$.next(columnStateList);
+  }
+
+  getDroppedFieldValue(field: keyof ImageFilterFormValue): string | [] {
+    return typeof this.filterFormValue$$.value[field] === 'string'
+      ? ''
+      : [];
+  }
+
+  checkIsPageFiltered(): void {
+    const isImageListFiltered = (<any>Object).values(this.filteredColumnState$$.value).some(item => Boolean(item));
+    this.isImageListFiltered$$.next(isImageListFiltered);
+  }
+
+  createActionDialogConfig(image: ImageModel, actionType: ImageActionType): ImageActionModalData {
+    const modalTitle = {
+      share: ModalTitle.share,
+      terminate: ModalTitle.terminate
+    };
+    return {
+      title: modalTitle[actionType],
+      actionType,
+      image,
+      isShared: this.isImageShared(image)
+    };
+  }
+
+  getRequestByAction(actionType): Function {
+    const callbackList = {
+      share: this.shareImageAllUsers,
+      terminate: this.terminateImage
+    };
+    return callbackList[actionType];
+  }
+
+  initImagePageInfo(imagePageInfo: ProjectImagesInfo): void {
+    this.getImagePageData(imagePageInfo.projectImagesInfos);
+    this.getDropdownDataList(imagePageInfo.filterData);
+    this.setFilterFormValue(imagePageInfo.imageFilter);
+    this.updateFilterColumnState(imagePageInfo.imageFilter);
+    this.checkIsPageFiltered();
+  }
+
+  createImageRequestInfo(image: ImageModel, userDataList?: UserData[]): ImageParams {
+    const { name, project, endpoint } = image;
+    const imageParams = {
+      imageName: name,
+      projectName: project,
+      endpoint: endpoint,
+    };
+
+    if (userDataList) {
+      imageParams['sharedWith'] = userDataList;
+    }
+    return imageParams;
+  }
+
+  getImageShareInfo(imageInfo: ImageParams): Observable<ShareDialogData> {
+    return this.userImagesPageService.getImageShareInfo(imageInfo);
+  }
+
+  getUserDataForShareDropdown(userData: string, imageInfo: ImageParams): Observable<UserData[]> {
+    return this.userImagesPageService.getUserDataForShareDropdown(imageInfo, userData);
+}
+
+  private isImageShared(image: ImageModel): boolean {
+    return image.sharingStatus !== SharingStatus.private;
+  }
+
+  private checkColumnState(acc: FilteredColumnList, fieldItem: FilterFormItemType): FilteredColumnList {
+    const [ fieldName, fieldValue ] = fieldItem;
+    let isColumnFiltered: boolean;
+    isColumnFiltered = typeof fieldValue === 'string' ? Boolean(fieldValue) : Boolean(fieldValue.length);
+    return  {...acc, [fieldName]: isColumnFiltered};
+  }
+
+  private filterFormValue(acc: ImageFilterFormValue, fieldItem: FilterFormItemType, exceptionValue: string = ''): ImageFilterFormValue {
+    const [ fieldName, fieldValue ] = fieldItem;
+    let value;
+
+    if (typeof fieldValue === 'string') {
+      value = fieldValue;
+    } else {
+      value = fieldValue.filter(item => item !== exceptionValue);
+    }
+    return {...acc, [fieldName]: value};
+  }
+
+  private filterByCondition(arr: ProjectModel[], field: keyof ImageModel, comparedValue: string) {
+    return arr.map(item => {
+      const filteredImageList = item.images.filter(image => image[field] === comparedValue);
+      return {...item, images: filteredImageList};
+    });
+  }
+
+  private updateCashedProjectList(projectList: ProjectModel[]): void {
+    this.cashedProjectList$$.next(projectList);
+  }
+
+  private getDropdownDataList(dropdownList: ImageFilterFormDropdownData): void {
+    this.addFilterDropdownData(dropdownList);
+    this.dropdownStartValue = dropdownList;
+  }
+
+  private addFilterDropdownData(data: ImageFilterFormDropdownData): void {
+    this.filterDropdownData$$.next(data);
+  }
+
+  private getImagePageData(imagePageData: ProjectModel[]): void {
+    const imageList = this.getImageList(imagePageData);
+    this.updateProjectList(imagePageData);
+    this.updateImageList(imageList);
+    this.updateCashedProjectList(imagePageData);
+    this.isProjectListEmpty$$.next(this.isProjectListEmpty(imagePageData));
+  }
+
+  private isProjectListEmpty(imagePageData: ProjectModel[]): boolean {
+    return imagePageData.every(({images}) => Boolean(!images.length));
+  }
+
+  private getImageList(imagePageData: ProjectModel[]): ImageModel[] {
+    return imagePageData.reduce((acc: ImageModel[], {images}) => [...acc, ...images], []);
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/images/index.ts b/services/self-service/src/main/resources/webapp/src/app/resources/images/index.ts
new file mode 100644
index 0000000..2451220
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/images/index.ts
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export * from './images.config';
+export * from './images.model';
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.html
index 738827b..1ffa7da 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.html
@@ -19,11 +19,11 @@
 
 <section class="table-wrapper resources-wrapper">
   <div class="table-wrapper scrolling">
-    <table 
-      mat-table 
-      [dataSource]="filteredEnvironments" 
+    <table
+      mat-table
+      [dataSource]="filteredEnvironments"
       multiTemplateDataRows
-      class="data-grid resources mat-elevation-z6" 
+      class="data-grid resources mat-elevation-z6"
       [trackBy]="trackBy"
     >
 
@@ -137,7 +137,7 @@
                 {{ element.name }}
               </span>
               <ng-template #odahu>
-                <span 
+                <span
                   [matTooltip]=" element.name "
                   matTooltipPosition="above"
                   (click)="printDetailOdahuModal(element)"
@@ -177,16 +177,16 @@
             </td>
 
             <td class="resources-col">
-              <computational-resources-list 
-                [resources]="element.resources" 
+              <computational-resources-list
+                [resources]="element.resources"
                 [environment]="element"
                 (buildGrid)="buildGrid()"
               ></computational-resources-list>
             </td>
             <td *ngIf="healthStatus?.billingEnabled" class="cost-col">
               <span class="total_cost">{{ element.billing?.report_lines?.length ? (element.cost | localcurrency) : 'N/A' }}</span>
-              <span 
-                (click)="element.billing && printCostDetails(element)" 
+              <span
+                (click)="element.billing && printCostDetails(element)"
                 class="currency_details"
                 [ngClass]="{ 'not-allowed' : !element.billing?.report_lines?.length }"
               >
@@ -195,9 +195,9 @@
             </td>
 
             <td class="settings">
-            <span 
-              #settings 
-              (click)="actions.toggle($event, settings)" 
+            <span
+              #settings
+              (click)="actions.toggle($event, settings)"
               class="actions"
               [ngClass]="{ 'disabled': element.status.toLowerCase() === 'creating'
                 || (element.image === 'docker.datalab-superset' && element.status !== 'running' && element.status !== 'stopped')
@@ -206,22 +206,22 @@
 
               <bubble-up #actions class="list-menu scrolling" position="bottom-left" alternative="top-left">
                 <ul class="list-unstyled" *ngIf="element.shape !== 'odahu cluster'">
-                  <div 
-                    class="active-items" 
+                  <div
+                    class="active-items"
                     *ngIf="element.status.toLowerCase() !== 'failed'
                       && element.status !== 'terminating'
                       && element.status !== 'terminated'
                       && element.status !== 'creating image'"
                   >
                     <li
-                      *ngIf="element.status !== 'stopped' && element.status !== 'stopping' 
-                        && element.status !== 'starting' && element.status !== 'creating image' 
+                      *ngIf="element.status !== 'stopped' && element.status !== 'stopping'
+                        && element.status !== 'starting' && element.status !== 'creating image'
                         && element.status.toLowerCase() !== 'reconfiguring'"
                       matTooltip="Unable to stop notebook because at least one compute is in progress"
-                      matTooltipPosition="above" 
+                      matTooltipPosition="above"
                       [matTooltipDisabled]="!isResourcesInProgress(element)"
                     >
-                      <div 
+                      <div
                         (click)="exploratoryAction(element, 'stop')"
                         [ngClass]="{'not-allowed': isResourcesInProgress(element) }"
                       >
@@ -229,31 +229,31 @@
                         <span>Stop</span>
                       </div>
                     </li>
-                    <li 
+                    <li
                       *ngIf="element.status.toLowerCase() === 'stopped' || element.status.toLowerCase() === 'stopping'"
-                      matTooltip="{{element.edgeNodeStatus !== 'running' 
-                        ? 'Unable to run notebook if edge node is not running.' 
-                        : 'Unable to run notebook until it will be stopped.'}}" 
+                      matTooltip="{{element.edgeNodeStatus !== 'running'
+                        ? 'Unable to start notebook if edge node is not running.'
+                        : 'Unable to start notebook until it will be stopped.'}}"
                       matTooltipPosition="above"
-                      [matTooltipDisabled]="!isResourcesInProgress(element) && element.status.toLowerCase() !== 'stopping' 
+                      [matTooltipDisabled]="!isResourcesInProgress(element) && element.status.toLowerCase() !== 'stopping'
                         && element.edgeNodeStatus === 'running'"
-                      [ngClass]="{'not-allow': isResourcesInProgress(element) || element.status.toLowerCase() === 'stopping' 
+                      [ngClass]="{'not-allow': isResourcesInProgress(element) || element.status.toLowerCase() === 'stopping'
                         || element.edgeNodeStatus !== 'running' }"
                     >
-                      <div 
+                      <div
                         (click)="exploratoryAction(element, 'run')"
-                        [ngClass]="{'not-allowed': isResourcesInProgress(element) || element.status.toLowerCase() === 'stopping' 
+                        [ngClass]="{'not-allowed': isResourcesInProgress(element) || element.status.toLowerCase() === 'stopping'
                           || element.edgeNodeStatus !== 'running' }">
                         <i class="material-icons">play_circle_outline</i>
-                        <span>Run</span>
+                        <span>Start</span>
                       </div>
                     </li>
-                    <li 
+                    <li
                       *ngIf="element.status.toLowerCase() === 'running' || element.status.toLowerCase() === 'stopped'"
                       matTooltip="Unable to terminate notebook because at least one compute is in progress"
                       matTooltipPosition="above" [matTooltipDisabled]="!isResourcesInProgress(element)"
                     >
-                      <div 
+                      <div
                         (click)="exploratoryAction(element, 'terminate')"
                         [ngClass]="{'not-allowed': isResourcesInProgress(element) }"
                       >
@@ -262,9 +262,13 @@
                       </div>
                     </li>
                     <li
-                      *ngIf="element.status === 'running' && element.image !== 'docker.datalab-superset' && element.image !== 'docker.datalab-jupyterlab'"
+                      *ngIf="element.status === 'running'
+                      && element.image !== 'docker.datalab-superset'
+                      && element.image !== 'docker.datalab-jupyterlab'
+                      && element.image !== 'docker.datalab-tensor-jupyterlab'
+                      && element.image !== 'docker.datalab-jupyter-gpu'"
                       matTooltip="Only one compute can be associated with analytical tool at a time"
-                      matTooltipPosition="above" 
+                      matTooltipPosition="above"
                       [matTooltipDisabled]="!element.activeCompute"
                       [matTooltipClass]="'full-size-tooltip'"
                       [ngClass]="{'not-allow': element.activeCompute }"
@@ -277,8 +281,8 @@
                         <span>Add compute</span>
                       </div>
                     </li>
-                    <li 
-                      (click)="exploratoryAction(element, 'schedule')" 
+                    <li
+                      (click)="exploratoryAction(element, 'schedule')"
                       *ngIf="element.status.toLowerCase() === 'running'
                         || element.status.toLowerCase() === 'stopped'"
                     >
@@ -290,14 +294,14 @@
                   </div>
                   <li
                     matTooltip="You can create an image after the library installation is complete"
-                    matTooltipPosition="above" 
+                    matTooltipPosition="above"
                     [matTooltipDisabled]="!checkLibStatus(element)"
                     [matTooltipClass]="'full-size-tooltip'"
-                    [ngClass]="{'not-allow': checkLibStatus(element) }" 
-                    *ngIf="element.status === 'running'  && element.image !== 'docker.datalab-superset' 
+                    [ngClass]="{'not-allow': checkLibStatus(element) }"
+                    *ngIf="element.status === 'running'  && element.image !== 'docker.datalab-superset'
                       && element.image !== 'docker.datalab-jupyterlab'"
                   >
-                    <div 
+                    <div
                       (click)="exploratoryAction(element, 'ami')"
                       [ngClass]="{'not-allowed': checkLibStatus(element) }"
                     >
@@ -305,7 +309,7 @@
                       <span>Create AMI</span>
                     </div>
                   </li>
-                  <li 
+                  <li
                     (click)="exploratoryAction(element, 'install')"
                     *ngIf="element.image !== 'docker.datalab-superset' && element.image !== 'docker.datalab-jupyterlab'"
                   >
@@ -314,19 +318,19 @@
                       <span>Manage libraries</span>
                     </div>
                   </li>
-                  <li *ngIf="element.status === 'running'" (click)="logAction(element.name)">
-                    <div>
-                      <a
-                        target="_blank"
-                        [attr.href]="'/#/terminal/' + element.private_ip + '/' + element.endpoint"
-                        class="navigate"
-                        (contextmenu)="false"
-                      >
-                        <i class="material-icons">laptop</i>
-                        <span>Open terminal</span>
-                      </a>
-                    </div>
-                  </li>
+<!--                  <li *ngIf="element.status === 'running'" (click)="logAction(element.name)">-->
+<!--                    <div>-->
+<!--                      <a-->
+<!--                        target="_blank"-->
+<!--                        [attr.href]="'/#/terminal/' + element.private_ip + '/' + element.endpoint"-->
+<!--                        class="navigate"-->
+<!--                        (contextmenu)="false"-->
+<!--                      >-->
+<!--                        <i class="material-icons">laptop</i>-->
+<!--                        <span>Open terminal</span>-->
+<!--                      </a>-->
+<!--                    </div>-->
+<!--                  </li>-->
                 </ul>
                 <ul class="list-unstyled" *ngIf="element.shape === 'odahu cluster'">
                   <li class="project-seting-item" *ngIf="element.status === 'stopped'" (click)="odahuAction(element, 'start')">
@@ -345,11 +349,11 @@
                       </a>
                     </div>
                   </li>
-                  <li 
+                  <li
                     class="project-seting-item"
-                    [ngClass]="{'disabled': element.status === 'stopped' || element.status.toLowerCase() === 'stopping' 
+                    [ngClass]="{'disabled': element.status === 'stopped' || element.status.toLowerCase() === 'stopping'
                       || element.status.toLowerCase() === 'starting'}"
-                    *ngIf="element.status === element.status !== 'terminated' && element.status !== 'terminating'" 
+                    *ngIf="element.status === element.status !== 'terminated' && element.status !== 'terminating'"
                     (click)="odahuAction(element, 'terminate')"
                   >
                     <div>
@@ -365,16 +369,16 @@
           </tr>
         </td>
       </ng-container>
-      
+
       <!-- FILTER START -->
       <ng-container matColumnDef="name-filter" sticky>
         <th mat-header-cell *matHeaderCellDef class="name-col filter-row-item ">
           <div class="input-wrapper">
-            <input 
-              placeholder="Filter by environment name" 
-              type="text" 
+            <input
+              placeholder="Filter by environment name"
+              type="text"
               class="form-control filter-field"
-              [value]="filterForm.name" 
+              [value]="filterForm.name"
               (input)="onFilterNameUpdate($event.target['value'])"
             />
           </div>
@@ -382,19 +386,19 @@
       </ng-container>
       <ng-container matColumnDef="status-filter">
         <th mat-header-cell *matHeaderCellDef class="status-col filter-row-item">
-          <multi-select-dropdown 
-            (selectionChange)="onUpdate($event)" 
+          <multi-select-dropdown
+            (selectionChange)="onUpdate($event)"
             [type]="'statuses'"
-            [items]="filterConfiguration.statuses" 
+            [items]="filterConfiguration.statuses"
             [model]="filterForm.statuses"
           ></multi-select-dropdown>
         </th>
       </ng-container>
       <ng-container matColumnDef="shape-filter">
         <th mat-header-cell *matHeaderCellDef class="shape-col filter-row-item">
-          <multi-select-dropdown 
+          <multi-select-dropdown
             (selectionChange)="onUpdate($event)"
-            [type]="'shapes'" 
+            [type]="'shapes'"
             [items]="filterConfiguration.shapes"
             [model]="filterForm.shapes"
           ></multi-select-dropdown>
@@ -405,10 +409,10 @@
       </ng-container>
       <ng-container matColumnDef="resource-filter">
         <th mat-header-cell *matHeaderCellDef class="resources-col filter-row-item">
-          <multi-select-dropdown 
-            (selectionChange)="onUpdate($event)" 
+          <multi-select-dropdown
+            (selectionChange)="onUpdate($event)"
             [type]="'resources'"
-            [items]="filterConfiguration.resources" 
+            [items]="filterConfiguration.resources"
             [model]="filterForm.resources"
           ></multi-select-dropdown>
         </th>
@@ -424,9 +428,9 @@
               <i class="material-icons">close</i>
             </button>
 
-            <button 
-              mat-icon-button 
-              class="btn apply" 
+            <button
+              mat-icon-button
+              class="btn apply"
               (click)="applyFilter_btnClick(filterForm)"
               [disabled]="!isFilterChanged"
             >
@@ -436,8 +440,8 @@
         </th>
       </ng-container>
       <ng-container matColumnDef="placeholder">
-        <td 
-          mat-footer-cell 
+        <td
+          mat-footer-cell
           *matFooterCellDef
           [colSpan]="!healthStatus?.billingEnabled ? displayedFilterColumns.length -1 : displayedFilterColumns.length"
           class="info"
@@ -453,9 +457,9 @@
 
       <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true" class="header-row"></tr>
 
-      <tr 
-        [hidden]="!collapseFilterRow" 
-        mat-header-row 
+      <tr
+        [hidden]="!collapseFilterRow"
+        mat-header-row
         *matHeaderRowDef="displayedFilterColumns; sticky: true"
         class="filter-row"
       ></tr>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.scss
index 6728ed7..fb8d96a 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.scss
@@ -200,7 +200,6 @@
 
   .actions-col {
     padding-right: 24px;
-    z-index: 5 !important;
     text-align: right;
     background-color: inherit;
 
@@ -396,7 +395,7 @@
 }
 
 .data-grid .list-menu li {
-  margin: 5px -5px;
+  //margin: 5px -5px;
   padding-bottom: 5px;
   font-size: 13px;
   border-bottom: 1px solid #edf1f5;
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.ts
index eccde3a..39a860c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.ts
@@ -17,7 +17,6 @@
  * under the License.
  */
 
-import { Project } from '../../administration/project/project.component';
 import {
   Component,
   EventEmitter,
@@ -32,14 +31,13 @@
 import { ExploratoryModel } from './resources-grid.model';
 import { FilterConfigurationModel } from './filter-configuration.model';
 import { GeneralEnvironmentStatus } from '../../administration/management/management.model';
-import { ConfirmationDialogType } from '../../shared';
+import { ConfirmationDialogComponent, ConfirmationDialogType } from '../../shared';
 import { SortUtils, CheckUtils } from '../../core/util';
 import { DetailDialogComponent } from '../exploratory/detail-dialog';
 import { AmiCreateDialogComponent } from '../exploratory/ami-create-dialog';
 import { InstallLibrariesComponent } from '../exploratory/install-libraries';
 import { ComputationalResourceCreateDialogComponent } from '../computational/computational-resource-create-dialog/computational-resource-create-dialog.component';
 import { CostDetailsDialogComponent } from '../exploratory/cost-details-dialog';
-import { ConfirmationDialogComponent } from '../../shared/modal-dialog/confirmation-dialog';
 import { SchedulerComponent } from '../scheduler';
 import { DICTIONARY } from '../../../dictionary/global.dictionary';
 import { ProgressBarService } from '../../core/services/progress-bar.service';
@@ -48,6 +46,7 @@
 import { AuditService } from '../../core/services/audit.service';
 import { CompareUtils } from '../../core/util/compareUtils';
 import { OdahuActionDialogComponent } from '../../shared/modal-dialog/odahu-action-dialog';
+import { Project } from '../../administration/project/project.model';
 
 export interface SharedEndpoint {
   edge_node_ip: string;
@@ -157,13 +156,16 @@
       .subscribe(
         (result: any) => {
           this.environments = ExploratoryModel.loadEnvironments(result);
+          if (this.environments?.length === 1) {
+            this.selectActiveProject(this.environments[0].project);
+          }
           this.getEnvironments.emit(this.environments);
           this.getBuckets();
           this.getDefaultFilterConfiguration();
           (this.environments.length) ? this.getUserPreferences() : this.filteredEnvironments = [];
           this.healthStatus && !this.healthStatus.billingEnabled && this.modifyGrid();
           this.progressBarService.stopProgressBar();
-        }, 
+        },
         () => this.progressBarService.stopProgressBar()
       );
   }
@@ -193,9 +195,9 @@
     this.buildGrid();
   }
 
-  public containsNotebook(notebook_name: string, envoirmentNames: Array<string>): boolean {
-    if (notebook_name && envoirmentNames.length ) {
-      return envoirmentNames
+  public containsNotebook(notebook_name: string, environmentNames: Array<string>): boolean {
+    if (notebook_name && environmentNames.length ) {
+      return environmentNames
         .some(item => CheckUtils.delimitersFiltering(notebook_name) === CheckUtils.delimitersFiltering(item));
     }
       return false;
@@ -228,10 +230,10 @@
 
   public printDetailEnvironmentModal(data): void {
     this.dialog.open(DetailDialogComponent, { data:
-      { 
-        notebook: data, 
-        bucketStatus: this.healthStatus.bucketBrowser, 
-        buckets: this.bucketsList, 
+      {
+        notebook: data,
+        bucketStatus: this.healthStatus.bucketBrowser,
+        buckets: this.bucketsList,
         type: 'resource'
       },
       panelClass: 'modal-lg'
@@ -252,12 +254,12 @@
   public exploratoryAction(data, action: string): void {
     const resource = this.getResourceByName(data.name, data.project);
     if (action === 'deploy') {
-      this.dialog.open(ComputationalResourceCreateDialogComponent, { data: 
-        { 
-          notebook: resource, 
-          full_list: this.environments 
-        }, 
-        panelClass: 'modal-xxl' 
+      this.dialog.open(ComputationalResourceCreateDialogComponent, { data:
+        {
+          notebook: resource,
+          full_list: this.environments
+        },
+        panelClass: 'modal-xxl'
       })
         .afterClosed().subscribe((res) => {
         res && this.buildGrid();
@@ -278,12 +280,12 @@
     } else if (action === 'terminate') {
       const compute =  data.resources.filter(cluster => cluster.status === 'running' || cluster.status === 'stopped');
       this.dialog.open(ConfirmationDialogComponent, { data:
-        { 
-          notebook: data, 
-          compute, 
-          type: ConfirmationDialogType.TerminateExploratory 
-        }, 
-        panelClass: 'modal-sm' 
+        {
+          notebook: data,
+          compute,
+          type: ConfirmationDialogType.TerminateExploratory
+        },
+        panelClass: 'modal-sm'
       })
         .afterClosed().subscribe((res) => res && this.buildGrid());
     } else if (action === 'install') {
@@ -306,8 +308,8 @@
           if (endpoint.status === 'ACTIVE') {
             const currEndpoint: SharedEndpoint = project.projectEndpoints[endpoint.name];
             const edgeItem: BucketList = {
-              name: `${project.project} (${endpoint.name})`, 
-              children: [], 
+              name: `${project.project} (${endpoint.name})`,
+              children: [],
               cloud: endpoint.cloudProvider
             };
             let projectBucket: string = currEndpoint.user_own_bicket_name
@@ -354,8 +356,8 @@
 
     data.filter(elem => elem.exploratory.map((item: any) => {
       if (shapes.indexOf(item.shape) === -1) shapes.push(item.shape);
-      if(item.gpu_type && gpuTypes.indexOf(item.gpu_type) === -1) gpuTypes.push(item.gpu_type);
-      if(item.gpu_count && gpuCounts.indexOf(`GPU count: ${item.gpu_count}`) === -1) gpuCounts.push(`GPU count: ${item.gpu_count}`);
+      if  (item.gpu_type && gpuTypes.indexOf(item.gpu_type) === -1) gpuTypes.push(item.gpu_type);
+      if  (item.gpu_count && gpuCounts.indexOf(`GPU count: ${item.gpu_count}`) === -1) gpuCounts.push(`GPU count: ${item.gpu_count}`);
       if (statuses.indexOf(item.status) === -1) statuses.push(item.status);
       statuses.sort(SortUtils.statusSort);
 
@@ -392,10 +394,12 @@
 
             const isName = item.name.toLowerCase().indexOf(config.name.toLowerCase()) !== -1;
             const isStatus = config.statuses.length > 0 ? (config.statuses.indexOf(item.status) !== -1) : (config.type !== 'active');
-            const isShape = config.shapes.length > 0 ? 
-                  (config.shapes.indexOf(item.shape) !== -1 ||
-                  config.shapes.indexOf(item.gpu_type) !== -1 ||
-                  config.shapes.indexOf(`GPU count: ${item.gpu_count}`) !== -1 ) : true;
+
+            const isShapeCondition = (config.shapes.indexOf(item.shape) !== -1 ||
+                                      config.shapes.indexOf(item.gpu_type) !== -1 ||
+                                      config.shapes.indexOf(`GPU count: ${item.gpu_count}`) !== -1 );
+
+            const isShape = config.shapes.length > 0 ? isShapeCondition : true;
 
             const modifiedResources = containsStatus(item.resources, config.resources);
             let isResources = config.resources.length > 0 ? (modifiedResources.length > 0) : true;
@@ -474,7 +478,7 @@
           }
           this.applyFilter_btnClick(result || this.filterForm);
           this.checkFilters();
-        }, 
+        },
         () => this.applyFilter_btnClick(null)
       );
   }
@@ -517,8 +521,8 @@
 
   public checkLibStatus(element) {
     let installingLib = [];
-    if(element.libs) {
-      installingLib = element.libs.filter(lib => lib.status === 'installing'); 
+    if (element.libs) {
+      installingLib = element.libs.filter(lib => lib.status === 'installing');
     }
     return !!installingLib.length;
   }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.model.ts b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.model.ts
index 8c8d8d7..64e5855 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.model.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.model.ts
@@ -148,10 +148,3 @@
     }
   }
 }
-
-// export interface Exploratory {
-//   project: string;
-//   endpoints: [];
-//   projectEndpoints: [];
-//   exploratory: ExploratoryModel[];
-// }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/resources.component.html
index 43aaf5a..23117f7 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/resources.component.html
@@ -26,9 +26,9 @@
         [matTooltipClass]="'full-size-tooltip'"
         [matTooltipDisabled]="healthStatus?.projectAssigned && resourcesGrid.activeProjectsList?.length !== 0"
       >
-        <button 
-          mat-raised-button 
-          class="butt butt-create" 
+        <button
+          mat-raised-button
+          class="butt butt-create"
           (click)="createEnvironment()"
           [disabled]="!healthStatus?.projectAssigned || !resourcesGrid.activeProjectsList?.length"
         >
@@ -36,23 +36,26 @@
         </button>
       </span>
       <div class="mat-reset">
-        <div class="control selector-wrapper" *ngIf="projects?.length">
+        <div class="control selector-wrapper" *ngIf="projects?.length"
+        [ngClass]="{'disabled-select': !isProjectsMoreThanOne}"
+        >
           <mat-form-field>
             <mat-label>Select project</mat-label>
 
-            <mat-select 
+            <mat-select
               disableOptionCentering
-              [(value)]="resourcesGrid.activeProject" 
+              [(value)]="resourcesGrid.activeProject"
               panelClass="top-select scrolling"
+              [disabled]="!isProjectsMoreThanOne"
             >
-              <mat-option 
-                *ngIf="projects?.length > 1" 
+              <mat-option
+                *ngIf="projects?.length > 1"
                 (click)="setActiveProject('')"
               >
                 Show all
               </mat-option>
-              <mat-option 
-                *ngFor="let project of projects" 
+              <mat-option
+                *ngFor="let project of projects"
                 [value]="project"
                 (click)="setActiveProject(project)"
               >
@@ -60,7 +63,7 @@
               </mat-option>
               <mat-option *ngIf="!projects?.length" class="multiple-select ml-10" disabled>Projects list is empty</mat-option>
             </mat-select>
-            <button class="caret">
+            <button class="caret" [disabled]="!isProjectsMoreThanOne">
               <i class="material-icons">keyboard_arrow_down</i>
             </button>
           </mat-form-field>
@@ -69,15 +72,15 @@
     </div>
 
     <div>
-      <span  
+      <span
         matTooltip="{{!this.bucketStatus?.view ? 'You have not permission to open bucket browser' : 'You have not any bucket'}}"
         matTooltipPosition="above"
         matTooltipDisabled="{{resourcesGrid.bucketsList?.length > 0 && this.bucketStatus?.view}}"
         [matTooltipClass]="'full-size-tooltip'"
       >
-        <button 
-          mat-raised-button 
-          class="butt butt-tool" 
+        <button
+          mat-raised-button
+          class="butt butt-tool"
           (click)="bucketBrowser(this.bucketStatus?.view)"
           [disabled]="!this.bucketStatus?.view || resourcesGrid.bucketsList?.length === 0"
         >
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/resources.component.scss
index c8f91ee..06e9ad4 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/resources.component.scss
@@ -36,3 +36,15 @@
     height: 38px;
   }
 }
+
+.disabled-select {
+  background-color: rgba(0, 0, 0, 0.12);
+  color: rgb(87, 114, 137);
+  opacity: 0.6;
+}
+
+.caret:disabled{
+  background-color: rgba(0, 0, 0, 0.12) !important;
+  color: rgb(87, 114, 137);
+  opacity: 0.6;
+}
\ No newline at end of file
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/resources.component.ts
index aea63c7..7ad2073 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/resources.component.ts
@@ -33,7 +33,7 @@
   styleUrls: ['./resources.component.scss']
 })
 
-export class ResourcesComponent implements OnInit, AfterViewInit {
+export class ResourcesComponent implements OnInit {
   public exploratoryEnvironments = [];
   public healthStatus: any;
   projects = [];
@@ -53,10 +53,6 @@
     this.projects = this.resourcesGrid.activeProjectsList;
   }
 
-  ngAfterViewInit() {
-
-  }
-
   public createEnvironment(): void {
     this.dialog.open(ExploratoryEnvironmentCreateComponent, { data: this.resourcesGrid, panelClass: 'modal-lg' })
       .afterClosed().subscribe(() => this.refreshGrid());
@@ -90,7 +86,7 @@
           bucketStatus: this.bucketStatus,
           buckets: this.resourcesGrid.bucketsList
         },
-        panelClass: 'modal-fullscreen' 
+        panelClass: 'modal-fullscreen'
       })
       .afterClosed().subscribe();
   }
@@ -100,7 +96,6 @@
   }
 
   public getActiveProject() {
-
     return this.resourcesGrid.activeProject;
   }
 
@@ -125,4 +120,8 @@
       error => this.toastr.error(error.message, 'Oops!')
     );
   }
+
+  get isProjectsMoreThanOne () {
+    return this.projects.length > 1;
+  }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources.module.ts b/services/self-service/src/main/resources/webapp/src/app/resources/resources.module.ts
index 47aea4c..fe9561f 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources.module.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/resources.module.ts
@@ -31,6 +31,16 @@
 import { BucketDataService } from './bucket-browser/bucket-data.service';
 import { ConvertFileSizePipeModule } from '../core/pipes/convert-file-size';
 import { BucketBrowserModule } from './bucket-browser/bucket-browser.module';
+import { ImagesComponent } from './images/images.component';
+import { CheckboxModule } from '../shared/checkbox';
+import { BubbleModule } from '../shared';
+import { IsElementAvailablePipeModule, NormalizeDropdownMultiValuePipeModule } from '../core/pipes';
+import { LocalDatePipeModule } from '../core/pipes/local-date-pipe';
+import { ImageActionDialogModule } from './exploratory/image-action-dialog/image-action-dialog.module';
+import { ImageDetailDialogModule } from './exploratory/image-detail-dialog/image-detail-dialog.module';
+import { LibraryInfoModalModule } from './exploratory/library-info-modal/library-info-modal.module';
+import { PageFilterComponent } from './exploratory/page-filter/page-filter.component';
+import { DirectivesModule } from '../core/directives';
 
 @NgModule({
   imports: [
@@ -42,13 +52,23 @@
     MaterialModule,
     MatTreeModule,
     ConvertFileSizePipeModule,
-    BucketBrowserModule
+    BucketBrowserModule,
+    CheckboxModule,
+    BubbleModule,
+    NormalizeDropdownMultiValuePipeModule,
+    LocalDatePipeModule,
+    ImageActionDialogModule,
+    ImageDetailDialogModule,
+    LibraryInfoModalModule,
+    DirectivesModule,
+    IsElementAvailablePipeModule,
   ],
   declarations: [
     ResourcesComponent,
     ManageUngitComponent,
     ConfirmDeleteAccountDialogComponent,
-
+    ImagesComponent,
+    PageFilterComponent,
   ],
   entryComponents: [ManageUngitComponent, ConfirmDeleteAccountDialogComponent],
   providers: [BucketDataService],
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/bubble/bubble.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/bubble/bubble.component.ts
index 02e8dde..86bcfaa 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/bubble/bubble.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/bubble/bubble.component.ts
@@ -17,17 +17,17 @@
  * under the License.
  */
 
-import { 
-  Component, 
-  Input, 
-  Output, 
-  EventEmitter, 
+import {
+  Component,
+  Input,
+  Output,
+  EventEmitter,
   HostBinding,
-  ChangeDetectorRef, 
-  ElementRef, 
+  ChangeDetectorRef,
+  ElementRef,
   OnDestroy,
-  ViewEncapsulation, 
-  HostListener 
+  ViewEncapsulation,
+  HostListener
 } from '@angular/core';
 import { BubblesCollector, BubbleService } from './bubble.service';
 
@@ -101,11 +101,14 @@
           this.changeDirection = !this.isInViewport(bubbleElem);
 
           let isBubbleOutOfWrapper;
-          
-          if(document.querySelector('.wrapper')) {
-            isBubbleOutOfWrapper = bubbleElem.getBoundingClientRect().bottom > document.querySelector('.wrapper').getBoundingClientRect().bottom;
+
+          if (document.querySelector('.wrapper')) {
+            isBubbleOutOfWrapper = bubbleElem.getBoundingClientRect()
+              .bottom > document.querySelector('.wrapper')
+              .getBoundingClientRect()
+              .bottom;
           }
-          
+
           (this.changeDirection || isBubbleOutOfWrapper) && this.bubbleService.updatePosition(element, bubbleElem, this.alternative);
         }
 
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/multi-level-select-dropdown/multi-level-select-dropdown.component.html b/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/multi-level-select-dropdown/multi-level-select-dropdown.component.html
index 1d6fda6..69daa4c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/multi-level-select-dropdown/multi-level-select-dropdown.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/multi-level-select-dropdown/multi-level-select-dropdown.component.html
@@ -51,13 +51,13 @@
               class="header-checkbox"
               [checked]="selectedAllInCattegory(item.type)"
               [someChecked]="selectedSomeInCattegory(item.type)"
-              (toggleSelection)="toggleselectedCategory(model, item.type)"
+              (toggleSelection)="toggleSelectedCategory(model, item.type)"
             ></datalab-checkbox>
-            {{labels[item.type] || item.type | titlecase}}
+            {{labels[item.type] || item.type | titlecase | underscoreless}}
           </a>
         </li>
 
-        <li 
+        <li
           class="role-item"
           role="presentation"
           *ngIf="model && isOpenCategory[item.type] && item.type !== 'COMPUTATIONAL_SHAPE' && item.type !== 'NOTEBOOK_SHAPE'"
@@ -75,9 +75,9 @@
             {{item.role}}
           </a>
         </li>
-        <li 
-          class="role-item" 
-          role="presentation" 
+        <li
+          class="role-item"
+          role="presentation"
           (click)="toggleItemsForCloud(item.type + item.cloud, $event)"
           *ngIf="model && isOpenCategory[item.type] && item.type === 'COMPUTATIONAL_SHAPE' && item.cloud !== items[i - 1].cloud
             || model && isOpenCategory[item.type] && item.type === 'NOTEBOOK_SHAPE' && item.type !== items[i - 1].type
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/multi-level-select-dropdown/multi-level-select-dropdown.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/multi-level-select-dropdown/multi-level-select-dropdown.component.ts
index 0a2300f..ff5e75a 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/multi-level-select-dropdown/multi-level-select-dropdown.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/form-controls/multi-level-select-dropdown/multi-level-select-dropdown.component.ts
@@ -20,6 +20,17 @@
 import { Input, Output, Component, EventEmitter } from '@angular/core';
 import { SortUtils } from '../../../core/util';
 
+export interface Rights {
+  role: string;
+  type: string;
+  cloud: string;
+}
+
+export enum TypeOfRights {
+  admin = 'ADMINISTRATION',
+  img = 'IMAGE'
+}
+
 @Component({
   selector: 'multi-level-select-dropdown',
   templateUrl: 'multi-level-select-dropdown.component.html',
@@ -29,7 +40,8 @@
 export class MultiLevelSelectDropdownComponent {
 
   @Input() items: Array<any>;
-  @Input() model: Array<any>;
+  @Input() model: Rights[];
+  @Input() isAddGroup: boolean = false;
   @Input() type: string;
   @Input() isAdmin: boolean;
   @Output() selectionChange: EventEmitter<{}> = new EventEmitter();
@@ -45,27 +57,28 @@
   };
   public selectedList: any;
 
-  constructor() {}
-
-  toggleSelectedOptions( model, value, event?) {
+  toggleSelectedOptions( model: Rights[], value: Rights, event?): void {
     if (event) event.preventDefault();
     const currRole = model.filter(v => v.role === value.role).length;
-    currRole ? this.model = model.filter(v => v.role !== value.role) : model.push(value);
+    currRole ? this.model = this.checkUserRights(model, value) : model.push(value);
     this.onUpdate(event);
   }
 
-  toggleselectedCategory( model, value, event?) {
+  toggleSelectedCategory(model: Rights[], value: string, event?): void {
     if (event) event.preventDefault();
     const categoryItems = this.items.filter(role => role.type === value);
-    this.selectedAllInCattegory(value) ? this.model = this.model.filter(role => role.type !== value) : categoryItems.forEach(role => {
-      if (!model.filter(mod => mod.role === role.role).length) {
-        this.model.push(role); 
-      }
-    });
+
+    this.selectedAllInCattegory(value)
+      ? this.model = this.checkUserRights(value)
+      : categoryItems.forEach(role => {
+        if (!model.filter(mod => mod.role === role.role).length) {
+          this.model.push(role);
+        }
+      });
     this.onUpdate(event);
   }
 
-  toggleSelectedCloud( model, category, cloud, event?) {
+  toggleSelectedCloud( model, category, cloud, event?): void {
     if (event) event.preventDefault();
     const categoryItems = this.items.filter(role => role.type === category && role.cloud === cloud);
     this.selectedAllInCloud(category, cloud) ? this.model = this.model.filter(role => {
@@ -79,14 +92,14 @@
     this.onUpdate(event);
   }
 
-  selectAllOptions($event) {
+  selectAllOptions($event): void {
     $event.preventDefault();
     this.model = [...this.items];
     this.onUpdate($event);
     $event.preventDefault();
   }
 
-  deselectAllOptions($event) {
+  deselectAllOptions($event): void {
     this.model = [];
     this.onUpdate($event);
     $event.preventDefault();
@@ -97,7 +110,7 @@
     this.selectionChange.emit({ model: this.model, type: this.type, $event });
   }
 
-  public toggleItemsForLable(label, $event) {
+  public toggleItemsForLable(label, $event): void {
     this.isOpenCategory[label] = !this.isOpenCategory[label];
     this.isCloudOpen[label + 'AWS'] = false;
     this.isCloudOpen[label + 'GCP'] = false;
@@ -105,40 +118,58 @@
     $event.preventDefault();
   }
 
-  public toggleItemsForCloud(label, $event) {
+  public toggleItemsForCloud(label, $event): void {
     this.isCloudOpen[label] = !this.isCloudOpen[label];
     $event.preventDefault();
   }
 
-  public selectedAllInCattegory(category) {
+  public selectedAllInCattegory(category): boolean {
     const selected = this.model.filter(role => role.type === category);
     const categoryItems = this.items.filter(role => role.type === category);
     return selected.length === categoryItems.length;
   }
 
-  public selectedSomeInCattegory(category) {
+  public selectedSomeInCattegory(category): boolean {
     const selected = this.model.filter(role => role.type === category);
     const categoryItems = this.items.filter(role => role.type === category);
     return selected.length && selected.length !== categoryItems.length;
   }
 
-  public selectedAllInCloud(category, cloud) {
+  public selectedAllInCloud(category, cloud): boolean {
     const selected = this.model.filter(role => role.type === category && role.cloud === cloud);
     const categoryItems = this.items.filter(role => role.type === category && role.cloud === cloud);
     return selected.length === categoryItems.length;
   }
 
-  public selectedSomeInCloud(category, cloud) {
+  public selectedSomeInCloud(category, cloud): boolean {
     const selected = this.model.filter(role => role.type === category && role.cloud === cloud);
     const categoryItems = this.items.filter(role => role.type === category && role.cloud === cloud);
     return selected.length && selected.length !== categoryItems.length;
   }
 
-  public checkInModel(item) {
-    return this.model.filter(v => v.role === item).length;
+  public checkInModel(item): boolean {
+    return !!this.model.filter(v => v.role === item).length;
   }
 
   public getSelectedRolesList() {
     return this.model.map(role => role.role);
   }
+
+  private checkUserRights(value: string): Rights[];
+  private checkUserRights(model: Rights[], value: Rights): Rights[];
+  private checkUserRights(...args: any[]): Rights[] {
+    if (args.length === 1) {
+      const [ value ] = args;
+
+      const filteredModelList = this.model.filter(role => role.type !== value);
+      const isNeedUncheckImage = value === TypeOfRights.admin && this.isAddGroup;
+      return isNeedUncheckImage ? filteredModelList.filter(role => role.type !== TypeOfRights.img) : filteredModelList;
+    } else {
+      const [model, value] = args;
+
+      const filteredModelList = model.filter(v => v.role !== value.role);
+      const isNeedUncheckImage = this.isAddGroup && value.type === TypeOfRights.admin;
+      return isNeedUncheckImage ? filteredModelList.filter(role => role.type !== TypeOfRights.img) : filteredModelList;
+    }
+  }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.scss b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.scss
index 1022888..dd85fe6 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.scss
@@ -1,21 +1,21 @@
-/*!
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
+  /*!
+  * Licensed to the Apache Software Foundation (ASF) under one
+  * or more contributor license agreements.  See the NOTICE file
+  * distributed with this work for additional information
+  * regarding copyright ownership.  The ASF licenses this file
+  * to you under the Apache License, Version 2.0 (the
+  * "License"); you may not use this file except in compliance
+  * with the License.  You may obtain a copy of the License at
+  *
+  *   http://www.apache.org/licenses/LICENSE-2.0
+  *
+  * Unless required by applicable law or agreed to in writing,
+  * software distributed under the License is distributed on an
+  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  * KIND, either express or implied.  See the License for the
+  * specific language governing permissions and limitations
+  * under the License.
+  */
 
 .confirmation-dialog {
   .content-box{
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/edge-action-dialog/edge-action-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/edge-action-dialog/edge-action-dialog.component.ts
index 244493d..5a11a04 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/edge-action-dialog/edge-action-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/edge-action-dialog/edge-action-dialog.component.ts
@@ -56,7 +56,7 @@
           </ul>
         </div>
         <ng-template #oneNode>
-          Edge node <span class="strong">{{data.item[0].name}}</span> wil be {{data.type === 'stop' ? 'stopped' : data.type === 'start' ? 'started' : 'recreated'}}
+          Edge node <span class="strong">{{data.item[0].name}}</span> will be {{data.type === 'stop' ? 'stopped' : data.type === 'start' ? 'started' : 'recreated'}}
         </ng-template>
 
       <p class="m-top-20 action-text"><span class="strong">Do you want to proceed?</span></p>
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/notification-dialog/notification-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/notification-dialog/notification-dialog.component.ts
index 2cdee43..4f532c0 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/notification-dialog/notification-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/notification-dialog/notification-dialog.component.ts
@@ -19,7 +19,8 @@
 
 import { Component, Inject } from '@angular/core';
 import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
-import {Endpoint} from '../../../administration/project/project.component';
+
+import { Endpoint } from '../../../administration/project/project.model';
 
 @Component({
   selector: 'notification-dialog',
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-btn/modal-btn.component.html b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-btn/modal-btn.component.html
new file mode 100644
index 0000000..0a5089c
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-btn/modal-btn.component.html
@@ -0,0 +1,34 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+<div class="component__wrapper">
+  <p *ngIf="needAdditionalQuestion" class="question center">
+    Do you want proceed?
+  </p>
+  <div class="button__wrapper">
+    <button type="button" class="butt mat-raised-button" (click)="close()">No</button>
+    <button
+      [disabled]="isConfirmBtnDisabled"
+      type="button"
+      class="butt butt-success mat-raised-button"
+      (click)="close(true)">
+      {{confirmBtnName}}
+    </button>
+  </div>
+</div>
+
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-btn/modal-btn.component.scss b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-btn/modal-btn.component.scss
new file mode 100644
index 0000000..d46002d
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-btn/modal-btn.component.scss
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+.button__wrapper {
+  text-align: center;
+}
+
+.question {
+  margin-bottom: 20px;
+  text-align: center;
+  color: #718ba6;
+  font-weight: bold;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-btn/modal-btn.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-btn/modal-btn.component.ts
new file mode 100644
index 0000000..4aa51fb
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-btn/modal-btn.component.ts
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+
+@Component({
+  selector: 'datalab-modal-btn',
+  templateUrl: './modal-btn.component.html',
+  styleUrls: ['./modal-btn.component.scss']
+})
+export class ModalBtnComponent {
+  @Input() isConfirmBtnDisabled: boolean;
+  @Input() confirmBtnName: string;
+  @Input() needAdditionalQuestion: boolean = false;
+
+  @Output() closeEvent: EventEmitter<boolean> = new EventEmitter<boolean>();
+
+  close(flag: boolean = false): void {
+    this.closeEvent.emit(flag);
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-header/modal-header.component.html b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-header/modal-header.component.html
new file mode 100644
index 0000000..83650e2
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-header/modal-header.component.html
@@ -0,0 +1,27 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF licenses this file
+  ~ to you under the Apache License, Version 2.0 (the
+  ~ "License"); you may not use this file except in compliance
+  ~ with the License.  You may obtain a copy of the License at
+  ~
+  ~   http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing,
+  ~ software distributed under the License is distributed on an
+  ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  ~ KIND, either express or implied.  See the License for the
+  ~ specific language governing permissions and limitations
+  ~ under the License.
+  -->
+
+<div>
+  <header class="dialog-header">
+    <h4 class="modal-title">
+      {{modalTitle}}
+    </h4>
+    <button type="button" class="close" (click)="onClose()">&times;</button>
+  </header>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-header/modal-header.component.scss b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-header/modal-header.component.scss
new file mode 100644
index 0000000..ece7004
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-header/modal-header.component.scss
@@ -0,0 +1,42 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+.dialog-header {
+  position: relative;
+  padding-left: 30px;
+  height: 50px;
+  background: #f6fafe;
+  line-height: 50px;
+}
+
+.close {
+  position: absolute;
+  top: 0;
+  right: 0;
+  height: 50px;
+  width: 50px;
+  font-size: 24px;
+  font-weight: 300;
+  border: 0;
+  background: none;
+  color: #577289;
+  outline: none;
+  cursor: pointer;
+  transition: all 0.5s ease-in-out;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-header/modal-header.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-header/modal-header.component.ts
new file mode 100644
index 0000000..7ef9b6d
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-header/modal-header.component.ts
@@ -0,0 +1,36 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+
+@Component({
+  selector: 'datalab-modal-header',
+  templateUrl: './modal-header.component.html',
+  styleUrls: ['./modal-header.component.scss']
+})
+export class ModalHeaderComponent {
+  @Input() modalTitle: string;
+
+  @Output() close: EventEmitter<any> = new EventEmitter<any>();
+
+  onClose(): void {
+    this.close.emit();
+  }
+
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-parts.module.ts b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-parts.module.ts
new file mode 100644
index 0000000..3559594
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-parts/modal-parts.module.ts
@@ -0,0 +1,40 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { ModalHeaderComponent } from './modal-header/modal-header.component';
+import { ModalBtnComponent } from './modal-btn/modal-btn.component';
+
+
+
+@NgModule({
+  declarations: [
+    ModalHeaderComponent,
+    ModalBtnComponent
+  ],
+  imports: [
+    CommonModule
+  ],
+  exports: [
+    ModalBtnComponent,
+    ModalHeaderComponent
+  ]
+})
+export class ModalPartsModule { }
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/index.ts b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/index.ts
index 0041163..9ab3d55 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/index.ts
@@ -26,6 +26,7 @@
 import { NotificationDialogModule } from '../modal-dialog/notification-dialog';
 import {EdgeActionDialogModule} from '../modal-dialog/edge-action-dialog';
 import {OdahuActionDialogModule} from '../modal-dialog/odahu-action-dialog';
+import { TruncateTextPipeModule } from '../../core/pipes/truncate-text-pipe';
 
 
 export * from './navbar.component';
@@ -39,7 +40,8 @@
     EdgeActionDialogModule,
     ProgressDialogModule,
     BubbleModule,
-    OdahuActionDialogModule
+    OdahuActionDialogModule,
+    TruncateTextPipeModule,
   ],
   declarations: [NavbarComponent],
   exports: [NavbarComponent, RouterModule]
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html
index 4c61dc9..78ea73c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html
@@ -28,8 +28,8 @@
       <span class="line"></span>
     </button>
 
-    <a [routerLink]="['/resources_list']" class="navbar-logo">
-      <img src="assets/svg/logo.svg" alt="">
+    <a [routerLink]="['/instances']" class="navbar-logo">
+      <img src="assets/svg/logo.svg" alt="datalab">
     </a>
   </div>
 
@@ -37,10 +37,16 @@
     <!-- <a *ngIf="healthStatus.status" [routerLink]="['/environment_management']" class="statusbar">
       <span class="material-icons" ngClass="{{healthStatus.status || ''}}">radio_button_checked</span>
     </a> -->
-    <a class="statusbar" #info (click)="actions.toggle($event, info)" *ngIf="metadata">
-      <span class="material-icons meta">info</span>
+
+    <a
+      *ngIf="metadata"
+      class="statusbar about-btn--wrapper"
+      #info
+      (click)="actions.toggle($event, info)">
+        <span class="about-btn">About</span>
     </a>
-    <bubble-up #actions class="list-menu" position="bottom-right">
+
+    <bubble-up #actions class="list-menu bubble-menu" position="bottom-left">
       <div class="app-info">
         <p>
           <strong>Version: </strong>
@@ -53,7 +59,7 @@
         <p>
           <strong>Revision: </strong>
           <span class="ellipsis commit" matTooltip="{{ metadata?.commit }}"
-            matTooltipPosition="above">{{ metadata?.commit }}</span>
+            matTooltipPosition="above">{{ metadata?.commit | truncateTextPipe: commitMaxLength }}</span>
         </p>
         <p>
           <a class="helper_instruction" [attr.href]="metadata?.release_notes" target="_blank">
@@ -61,55 +67,127 @@
         </p>
       </div>
     </bubble-up>
-    <button class="btn btn-logout ani" (click)="logout_btnClick()">
-      Log out <span class="user-name">{{currentUserName}}</span>
-    </button>
+
+    <span class="help-link--wrapper">
+      <a class="help-link" href="https://github.com/apache/incubator-datalab/blob/master/USER_GUIDE.md" target="_blank">Help</a>
+    </span>
+
+    <span
+      class="material-icons account-icon--nav-bar account-icon" #login (click)="loginInfo.toggle($event, login)">
+        account_circle
+    </span>
+    <bubble-up class="user-info-popup__conponent" #loginInfo position="bottom-left">
+      <div class="user-info-popup--wrapper">
+        <span class="material-icons account-icon--buble">
+          account_circle
+        </span>
+        <span class="user-name">{{userData.name}}</span>
+        <span class="user-mail">{{userData.email}}</span>
+        <button type="button" class="logout-btn" (click)="logout_btnClick()">
+          Log out from account
+        </button>
+      </div>
+    </bubble-up>
   </div>
 </div>
 
 <mat-sidenav-container class="example-container" autosize >
-  <mat-sidenav 
-    #drawer 
-    mode="side" 
-    opened 
-    role="navigation" 
-    [style.width]="isExpanded ? '220px' : '60px'" 
-    disableClose 
+  <mat-sidenav
+    #drawer
+    mode="side"
+    opened
+    role="navigation"
+    [style.width]="isExpanded ? '220px' : '60px'"
+    disableClose
     *ngIf="healthStatus"
   >
     <mat-nav-list >
       <nav>
         <div>
-          <a 
-            class="nav-item" 
-            [routerLink]="['/resources_list']" 
-            [routerLinkActive]="['active']"
-            [routerLinkActiveOptions]="{exact:true}"
-          >
-            <span *ngIf="isExpanded; else resources">List of Resources</span>
-            <ng-template #resources><i class="material-icons">dashboard</i></ng-template>
+          <a class="nav-item has-children">
+            <span *ngIf="isExpanded">{{sideBarNames.resources}}</span>
+            <a
+              class="sub-nav-item"
+              [style.margin-left.px]="isExpanded ? '30' : '0'"
+              [routerLink]="[routerList.instances]"
+              [routerLinkActive]="['active']"
+              [routerLinkActiveOptions]="{exact:true}"
+            >
+              <span *ngIf="isExpanded; else instances">{{sideBarNames.instances}}</span>
+              <ng-template #instances><i class="material-icons">laptop</i></ng-template>
+            </a>
+
+            <a
+              class="sub-nav-item"
+              [style.margin-left.px]="isExpanded ? '30' : '0'"
+              [routerLink]="[routerList.images]"
+              [routerLinkActive]="['active']"
+              [routerLinkActiveOptions]="{exact:true}"
+            >
+              <span *ngIf="isExpanded; else images">{{sideBarNames.images}}</span>
+              <ng-template #images><i class="material-icons">photo</i></ng-template>
+            </a>
+
+            <a
+              *ngIf="healthStatus.connectedPlatforms?.view"
+              class="sub-nav-item"
+              [style.margin-left.px]="isExpanded ? '30' : '0'"
+              [routerLink]="[routerList.connectedPlatforms]"
+              [routerLinkActive]="['active']"
+              [routerLinkActiveOptions]="{exact:true}"
+            >
+              <span *ngIf="isExpanded; else connectedPlatforms">{{sideBarNames.connectedPlatforms}}</span>
+              <ng-template #connectedPlatforms><i class="material-icons">cast</i></ng-template>
+            </a>
+
+          </a>
+
+          <a class="nav-item has-children" *ngIf="healthStatus?.billingEnabled || healthStatus?.auditEnabled">
+            <span *ngIf="isExpanded">{{sideBarNames.reports}}</span>
+            <a
+              *ngIf="healthStatus?.auditEnabled"
+              class="sub-nav-item"
+              [routerLink]="[routerList.audit]"
+              [style.margin-left.px]="isExpanded ? '30' : '0'"
+              [routerLinkActive]="['active']"
+              [routerLinkActiveOptions]="{exact:true}"
+            >
+              <span *ngIf="isExpanded; else audit">{{sideBarNames.audit}}</span>
+              <ng-template #audit><i class="material-icons">library_books</i></ng-template>
+            </a>
+            <a
+              *ngIf="healthStatus?.billingEnabled"
+              class="sub-nav-item"
+              [routerLink]="[routerList.billing]"
+              [routerLinkActive]="['active']"
+              [routerLinkActiveOptions]="{exact:true}"
+              [style.margin-left.px]="isExpanded ? '30' : '0'"
+            >
+              <span *ngIf="isExpanded; else billing">{{sideBarNames.billing}}</span>
+              <ng-template #billing><i class="material-icons">account_balance_wallet</i></ng-template>
+            </a>
           </a>
           <a class="nav-item has-children" *ngIf="healthStatus?.admin || healthStatus?.projectAdmin">
-            <span *ngIf="isExpanded">Administration</span>
+            <span *ngIf="isExpanded">{{sideBarNames.administration}}</span>
 
-            <a 
-              class="sub-nav-item" 
-              [style.margin-left.px]="isExpanded ? '30' : '0'" 
-              [routerLink]="['/roles']"
-              [routerLinkActive]="['active']" 
+            <a
+              class="sub-nav-item"
+              [style.margin-left.px]="isExpanded ? '30' : '0'"
+              [routerLink]="[routerList.users]"
+              [routerLinkActive]="['active']"
               [routerLinkActiveOptions]="{exact:true}"
             >
-              <span *ngIf="isExpanded; else roles">Roles</span>
+              <span *ngIf="isExpanded; else roles">{{sideBarNames.users}}</span>
               <ng-template #roles><i class="material-icons">account_box</i></ng-template>
             </a>
-            <a 
-              class="sub-nav-item" 
-              [style.margin-left.px]="isExpanded ? '30' : '0'" 
-              [routerLink]="['/projects']"
-              [routerLinkActive]="['active']" 
+            <a
+              class="sub-nav-item"
+              [style.margin-left.px]="isExpanded ? '30' : '0'"
+              [routerLink]="[routerList.projects]"
+              [routerLinkActive]="['active']"
               [routerLinkActiveOptions]="{exact:true}"
             >
-              <span *ngIf="isExpanded; else projects">Projects</span>
+              <span *ngIf="isExpanded; else projects">{{sideBarNames.projects}}</span>
               <ng-template #projects><i class="material-icons">dns</i></ng-template>
             </a>
             <!--            <a class="sub-nav-item" [style.margin-left.px]="isExpanded ? '30' : '0'" [routerLink]="['/odahu']"-->
@@ -117,53 +195,29 @@
             <!--              <span *ngIf="isExpanded; else odahu">Odahu deployment</span>-->
             <!--              <ng-template #odahu><i class="material-icons">get_app</i></ng-template>-->
             <!--            </a>-->
-            <a 
-              class="sub-nav-item" 
+            <a
+              class="sub-nav-item"
               [style.margin-left.px]="isExpanded ? '30' : '0'"
-              [routerLink]="['/environment_management']" 
+              [routerLink]="[routerList.resources]"
               [routerLinkActive]="['active']"
               [routerLinkActiveOptions]="{exact:true}"
             >
-              <span *ngIf="isExpanded; else env">Environment Management</span>
+              <span *ngIf="isExpanded; else env">{{sideBarNames.resources}}</span>
               <ng-template #env><i class="material-icons">settings</i></ng-template>
             </a>
-            <a 
-              *ngIf="healthStatus?.admin" 
-              class="sub-nav-item" 
+            <a
+              *ngIf="healthStatus?.admin"
+              class="sub-nav-item"
               [style.margin-left.px]="isExpanded ? '30' : '0'"
-              [routerLink]="['/configuration']" 
+              [routerLink]="[routerList.configuration]"
               [routerLinkActive]="['active']"
               [routerLinkActiveOptions]="{exact:true}"
             >
-              <span *ngIf="isExpanded; else env">Configuration</span>
+              <span *ngIf="isExpanded; else env">{{sideBarNames.configuration}}</span>
               <ng-template #env><i class="material-icons">build_circle</i></ng-template>
             </a>
           </a>
-          <a class="nav-item has-children" *ngIf="healthStatus?.billingEnabled || healthStatus?.auditEnabled">
-            <span *ngIf="isExpanded">Reports</span>
-            <a 
-              *ngIf="healthStatus?.auditEnabled" 
-              class="sub-nav-item" 
-              [routerLink]="['/audit']" 
-              [style.margin-left.px]="isExpanded ? '30' : '0'"
-              [routerLinkActive]="['active']" 
-              [routerLinkActiveOptions]="{exact:true}"
-            >
-              <span *ngIf="isExpanded; else audit">Audit</span>
-              <ng-template #audit><i class="material-icons">library_books</i></ng-template>
-            </a>
-            <a 
-              *ngIf="healthStatus?.billingEnabled" 
-              class="sub-nav-item" 
-              [routerLink]="['/billing_report']"
-              [routerLinkActive]="['active']" 
-              [routerLinkActiveOptions]="{exact:true}" 
-              [style.margin-left.px]="isExpanded ? '30' : '0'"
-            >
-              <span *ngIf="isExpanded; else billing">Billing</span>
-              <ng-template #billing><i class="material-icons">account_balance_wallet</i></ng-template>
-            </a>
-          </a>
+
         </div>
         <!--        <div>-->
         <!--          <a class="nav-item" [routerLink]="['/swagger']" [routerLinkActive]="['active']"-->
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.scss b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.scss
index 3d99f7d..11ecd7f 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.scss
@@ -129,7 +129,6 @@
 
   p {
     strong {
-      display: inline-block;
       width: 120px;
       color: #455c74;
       font-size: 14px;
@@ -145,7 +144,6 @@
     }
 
     span {
-      display: inline-block;
       width: 180px;
       vertical-align: bottom;
     }
@@ -332,3 +330,70 @@
 .blue {
   color: #35afd5;
 }
+
+.account-icon {
+  margin-right: 20px;
+  color: white;
+  font-size: 34px;
+  cursor: pointer;
+}
+
+.statusbar.about-btn--wrapper > span.about-btn {
+  font-size: 16px;
+  background-color: transparent;
+  color: white;
+  border: none;
+  outline: none;
+}
+
+.help-link {
+  color: white;
+  font-size: 16px;
+
+  &--wrapper {
+    margin-right: 20px;
+  }
+}
+
+.about-btn--wrapper {
+  margin-right: 20px;
+}
+
+.user-info-popup{
+  &__conponent.bubble-up {
+    width: 300px;
+    height: 180px;
+    top: 48px !important;
+    box-shadow: none;
+    border: 1px solid #36afd5;
+  }
+}
+
+.user-info-popup--wrapper {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: space-between;
+  height: 100%;
+  padding: 15px 5px;
+}
+
+.account-icon--buble {
+  color: #36afd5;
+  font-size: 40px;
+}
+
+.logout-btn {
+  padding: 5px 10px;
+  color: white;
+  background-color: #36afd5;
+  border: none;
+  outline: none;
+  border-radius: 5px;
+  cursor: pointer;
+}
+
+.bubble-menu.bubble-up {
+  width: 300px;
+  top: 48px !important;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.ts
index 95907e7..56b634c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.ts
@@ -23,12 +23,12 @@
 import { ToastrService } from 'ngx-toastr';
 import { RouterOutlet } from '@angular/router';
 
-import { 
-  ApplicationSecurityService, 
-  HealthStatusService, 
-  AppRoutingService, 
-  SchedulerService, 
-  StorageService 
+import {
+  ApplicationSecurityService,
+  HealthStatusService,
+  AppRoutingService,
+  SchedulerService,
+  StorageService
 } from '../../core/services';
 import { GeneralEnvironmentStatus } from '../../administration/management/management.model';
 import { NotificationDialogComponent } from '../modal-dialog/notification-dialog';
@@ -37,11 +37,13 @@
   animate,
   transition,
   style,
-  query, 
+  query,
   group,
 } from '@angular/animations';
 import {skip, take} from 'rxjs/operators';
 import {ProgressBarService} from '../../core/services/progress-bar.service';
+import {Sidebar_Names_Config, UserInfo} from './navbar.config';
+import { RoutingListConfig } from '../../core/configs/routing-list.config';
 
 interface Quota {
   projectQuotas: {};
@@ -84,6 +86,7 @@
 
   private readonly CHECK_ACTIVE_SCHEDULE_TIMEOUT: number = 300000;
   private readonly CHECK_ACTIVE_SCHEDULE_PERIOD: number = 15;
+  readonly routerList: typeof RoutingListConfig = RoutingListConfig;
 
   currentUserName: string;
   quotesLimit: number = 70;
@@ -92,6 +95,9 @@
   isExpanded: boolean = true;
   healthStatus: GeneralEnvironmentStatus;
   subscriptions: Subscription = new Subscription();
+  sideBarNames: typeof Sidebar_Names_Config = Sidebar_Names_Config;
+  userData!: UserInfo;
+  commitMaxLength: number = 22;
 
   constructor(
     public toastr: ToastrService,
@@ -121,6 +127,7 @@
         this.checkVersionData();
       }
     });
+    this.userData = this.getUserData();
   }
 
   ngOnDestroy(): void {
@@ -198,6 +205,17 @@
     }
   }
 
+  private getUserData(): UserInfo {
+    const token = localStorage.getItem('JWT_TOKEN');
+    const [_, tokenInfo] = token.split('.');
+    const {name, email} = JSON.parse(atob(tokenInfo));
+
+    return {
+      name: name || 'Jhon Doe',
+      email: email || 'Email not found'
+    };
+  }
+
   private checkAssignment(params): void {
     if (this.dialog.openDialogs.length > 0) return;
     this.emitQuotes('permissions');
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.config.ts b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.config.ts
new file mode 100644
index 0000000..84f1a6a
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.config.ts
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+export enum Sidebar_Names_Config {
+  reports = 'Reports',
+  audit = 'Audit',
+  billing = 'Billing',
+  administration = 'Administration',
+  users = 'Users',
+  projects = 'Projects',
+  resources = 'Resources',
+  configuration = 'Configuration',
+  instances = 'Instances',
+  images = 'Images',
+  connectedPlatforms = 'Connected platforms'
+}
+
+export interface UserInfo {
+  email: string;
+  name: string;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/time-picker/index.ts b/services/self-service/src/main/resources/webapp/src/app/shared/time-picker/index.ts
index 4133045..0fe6caa 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/time-picker/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/time-picker/index.ts
@@ -33,7 +33,7 @@
 export * from './time-picker.component';
 
 @NgModule({
-    imports: [CommonModule, FormsModule, ReactiveFormsModule, MaterialModule, LocalDatePipeModule],
+  imports: [CommonModule, FormsModule, ReactiveFormsModule, MaterialModule, LocalDatePipeModule],
   declarations: [TimePickerComponent, TimePickerDialogComponent, TimeCoverComponent, TickerComponent],
   entryComponents: [TimePickerDialogComponent],
   exports: [TimePickerComponent]
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/time-picker/ticker.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/time-picker/ticker.component.ts
index 45931f1..623fc18 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/time-picker/ticker.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/time-picker/ticker.component.ts
@@ -38,12 +38,12 @@
           <button mat-mini-fab class="ticker-selected"></button>
         </mat-toolbar>
         <div *ngFor="let step of steps; let i = index" [class]="getTimeValueClass(step, i)" >
-          <button 
-            mat-mini-fab 
+          <button
+            mat-mini-fab
             [color]="selectedTimePart === step ? color : ''"
             (click)="changeTimeValue(step)"
-          > 
-            {{ step }} 
+          >
+            {{ step }}
           </button>
         </div>
       </div>
diff --git a/services/self-service/src/main/resources/webapp/src/assets/styles/_dialogs.scss b/services/self-service/src/main/resources/webapp/src/assets/styles/_dialogs.scss
index 2802945..9f997be 100644
--- a/services/self-service/src/main/resources/webapp/src/assets/styles/_dialogs.scss
+++ b/services/self-service/src/main/resources/webapp/src/assets/styles/_dialogs.scss
@@ -159,10 +159,6 @@
         transition: all 0.45s ease-in-out;
         line-height: 19px;
 
-        &.spark-url {
-          line-height: 16px;
-        }
-
         &:hover {
           color: #5faec7;
         }
diff --git a/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss b/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss
index becd4a2..e78e6ba 100644
--- a/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss
+++ b/services/self-service/src/main/resources/webapp/src/assets/styles/_theme.scss
@@ -147,7 +147,7 @@
 }
 
 .audit {
-  .select-wrapper {
+  .select__wrapper {
     .mat-reset {
       .selector-wrapper {
         height: 25px;
@@ -1056,8 +1056,8 @@
   }
 }
 .configuration-wrapper {
-  box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2), 
-              0px 6px 10px 0px rgba(0, 0, 0, 0.14), 
+  box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.2),
+              0px 6px 10px 0px rgba(0, 0, 0, 0.14),
               0px 1px 18px 0px rgba(0, 0, 0, 0.12);
 
   .mat-tab-header {
diff --git a/services/self-service/src/main/resources/webapp/src/dictionary/azure.dictionary.ts b/services/self-service/src/main/resources/webapp/src/dictionary/azure.dictionary.ts
index 1619ffd..bcfa5f0 100644
--- a/services/self-service/src/main/resources/webapp/src/dictionary/azure.dictionary.ts
+++ b/services/self-service/src/main/resources/webapp/src/dictionary/azure.dictionary.ts
@@ -30,7 +30,7 @@
     'slave_node_shape': 'azure_dataengine_slave_size',
     'total_instance_number': 'dataengine_instance_count',
     'spot_instance': 'Low-priority virtual machines',
-    'cluster_version': '',
+    'cluster_version': 'hdinsight_version',
     'max_cluster_name_length': 10,
     'billing': {
         'resourceName': 'resourceName',
@@ -57,10 +57,8 @@
     'datalake_user_directory_name': 'datalake_user_directory_name',
     'datalake_shared_directory_name': 'datalake_shared_directory_name',
     'docker.datalab-dataengine-service': {
-        'total_instance_number_min': 'min_emr_instance_count',
-        'total_instance_number_max': 'max_emr_instance_count',
-        'min_emr_spot_instance_bid_pct': 'min_emr_spot_instance_bid_pct',
-        'max_emr_spot_instance_bid_pct': 'max_emr_spot_instance_bid_pct',
+        'total_instance_number_min': 'min_hdinsight_instance_count',
+        'total_instance_number_max': 'max_hdinsight_instance_count',
         'master_node_shape': 'master_node_shape',
         'slave_node_shape': 'slave_node_shape',
         'total_instance_number': 'total_instance_number',
diff --git a/services/self-service/src/main/resources/webapp/src/styles.scss b/services/self-service/src/main/resources/webapp/src/styles.scss
index 00a27bb..147661e 100644
--- a/services/self-service/src/main/resources/webapp/src/styles.scss
+++ b/services/self-service/src/main/resources/webapp/src/styles.scss
@@ -121,6 +121,7 @@
   text-align: left;
 }
 
+.created,
 .running,
 .starting,
 .installed,
@@ -402,7 +403,8 @@
 }
 #scrolling,
 .scrolling,
-ace_scrollbar {
+ace_scrollbar,
+.library-dialog-container .mat-dialog-container {
   scrollbar-width: thin;
 }
 
@@ -571,3 +573,12 @@
 .timezone-mat-select {
   max-width: 350px !important;
 }
+
+.library-dialog-container .mat-dialog-container {
+  width: 300px;
+  max-height: 210px;
+}
+
+.library-dialog-container ::-webkit-scrollbar {
+  width: 3px !important;
+}
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/AuditResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/AuditResourceTest.java
index f7fc60f..cd6355b 100644
--- a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/AuditResourceTest.java
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/AuditResourceTest.java
@@ -21,6 +21,7 @@
 
 import com.epam.datalab.backendapi.domain.AuditCreateDTO;
 import com.epam.datalab.backendapi.domain.AuditResourceTypeEnum;
+import com.epam.datalab.backendapi.resources.dto.AuditFilter;
 import com.epam.datalab.backendapi.service.AuditService;
 import io.dropwizard.auth.AuthenticationException;
 import io.dropwizard.testing.junit.ResourceTestRule;
@@ -34,12 +35,11 @@
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import java.util.ArrayList;
+import java.util.StringJoiner;
+
 import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.refEq;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.*;
 
 public class AuditResourceTest extends TestBase {
 
@@ -82,7 +82,50 @@
         assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
     }
 
+    @Test
+    public void downloadAuditReport() {
+        when(auditService.downloadAuditReport(getAuditFilter())).thenReturn(getAuditReport());
+        final Response response = resources.getJerseyTest()
+                .target("/audit/report/download")
+                .request()
+                .header("Authorization", "Bearer " + TOKEN)
+                .post(Entity.json(getAuditFilter()));
+
+        assertEquals(HttpStatus.SC_OK, response.getStatus());
+        assertEquals(getAuditReport(), response.readEntity(String.class));
+        assertEquals(MediaType.APPLICATION_OCTET_STREAM, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+
+        verify(auditService).downloadAuditReport(refEq(getAuditFilter()));
+        verifyNoMoreInteractions(auditService);
+    }
+
     private AuditCreateDTO prepareAuditCreateDTO() {
         return new AuditCreateDTO(RESOURCE, INFO, AuditResourceTypeEnum.COMPUTE);
     }
+
+    private String getAuditReport() {
+        StringBuilder auiditReport = new StringBuilder();
+        auiditReport.append("\"Available reporting period from: ").append("17-Mar-2022 ").append("to: ").append("20-Mar-2022").append("\"\n");
+        auiditReport.append(new StringJoiner(",").add("Date").add("User").add("Action").add("Project").add("Resource type").add("Resource\n"));
+        auiditReport.append(new StringJoiner(",").add("2022-03-20").add("test").add("LOG_IN").add("").add("").add("\n"));
+        auiditReport.append(new StringJoiner(",").add("2022-03-20").add("test").add("LOG_IN").add("").add("").add("\n"));
+        auiditReport.append(new StringJoiner(",").add("2022-03-19").add("test").add("LOG_IN").add("").add("").add("\n"));
+        auiditReport.append(new StringJoiner(",").add("2022-03-17").add("test").add("LOG_IN").add("").add("").add("\n"));
+
+        return auiditReport.toString();
+    }
+
+    private AuditFilter getAuditFilter() {
+        AuditFilter auditFilter = new AuditFilter();
+        auditFilter.setUsers(new ArrayList<>());
+        auditFilter.setResourceNames(new ArrayList<>());
+        auditFilter.setResourceTypes(new ArrayList<>());
+        auditFilter.setProjects(new ArrayList<>());
+        auditFilter.setLocale("en-GB");
+        auditFilter.setPageSize(50);
+        auditFilter.setPageNumber(1);
+        auditFilter.setDateStart("2022-03-17");
+        auditFilter.setDateEnd("2022-03-20");
+        return auditFilter;
+    }
 }
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ExploratoryResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ExploratoryResourceTest.java
index 0f2a8f0..3577798 100644
--- a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ExploratoryResourceTest.java
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ExploratoryResourceTest.java
@@ -23,6 +23,7 @@
 import com.epam.datalab.backendapi.resources.dto.ExploratoryActionFormDTO;
 import com.epam.datalab.backendapi.resources.dto.ExploratoryCreateFormDTO;
 import com.epam.datalab.backendapi.service.ExploratoryService;
+import com.epam.datalab.backendapi.service.ImageExploratoryService;
 import com.epam.datalab.dto.aws.computational.ClusterConfig;
 import com.epam.datalab.exceptions.DatalabException;
 import com.epam.datalab.model.exploratory.Exploratory;
@@ -59,9 +60,10 @@
 public class ExploratoryResourceTest extends TestBase {
 
     private ExploratoryService exploratoryService = mock(ExploratoryService.class);
+    private ImageExploratoryService imageExploratoryService = mock(ImageExploratoryService.class);
 
     @Rule
-    public final ResourceTestRule resources = getResourceTestRuleInstance(new ExploratoryResource(exploratoryService));
+    public final ResourceTestRule resources = getResourceTestRuleInstance(new ExploratoryResource(exploratoryService,imageExploratoryService));
 
     @Before
     public void setup() throws AuthenticationException {
@@ -297,7 +299,7 @@
         ecfDto.setName("someName");
         ecfDto.setShape("someShape");
         ecfDto.setVersion("someVersion");
-        ecfDto.setImageName("someImageName");
+        //ecfDto.setImageName("someImageName");
         ecfDto.setProject("project");
         ecfDto.setEndpoint("endpoint");
         return ecfDto;
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ImageExploratoryResourceTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ImageExploratoryResourceTest.java
index f62b1e3..bc50266 100644
--- a/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ImageExploratoryResourceTest.java
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/resources/ImageExploratoryResourceTest.java
@@ -24,6 +24,7 @@
 import com.epam.datalab.backendapi.resources.dto.ExploratoryImageCreateFormDTO;
 import com.epam.datalab.backendapi.resources.dto.ImageInfoRecord;
 import com.epam.datalab.backendapi.service.ImageExploratoryService;
+import com.epam.datalab.cloud.CloudProvider;
 import com.epam.datalab.dto.exploratory.ImageStatus;
 import com.epam.datalab.exceptions.ResourceAlreadyExistException;
 import com.epam.datalab.exceptions.ResourceNotFoundException;
@@ -40,6 +41,7 @@
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import java.util.Collections;
+import java.util.Date;
 import java.util.List;
 
 import static org.junit.Assert.assertEquals;
@@ -54,7 +56,6 @@
 import static org.mockito.Mockito.when;
 
 public class ImageExploratoryResourceTest extends TestBase {
-    private final static String AUDIT_MESSAGE = "Create image: %s";
     private static final String PROJECT = "projectName";
     private ImageExploratoryService imageExploratoryService = mock(ImageExploratoryService.class);
     private RequestId requestId = mock(RequestId.class);
@@ -70,7 +71,7 @@
 
     @Test
     public void createImage() {
-        when(imageExploratoryService.createImage(any(UserInfo.class), anyString(), anyString(), anyString(), anyString(), anyString()))
+        when(imageExploratoryService.createImage(any(UserInfo.class), anyString(), anyString(), anyString(), anyString()))
                 .thenReturn("someUuid");
         when(requestId.put(anyString(), anyString())).thenReturn("someUuid");
         final Response response = resources.getJerseyTest()
@@ -83,7 +84,7 @@
         assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
         verify(imageExploratoryService).createImage(getUserInfo(), PROJECT, "someNotebookName",
-                "someImageName", "someDescription", String.format(AUDIT_MESSAGE, "someImageName"));
+                "someImageName", "someDescription");
         verify(requestId).put(USER.toLowerCase(), "someUuid");
         verifyNoMoreInteractions(imageExploratoryService, requestId);
     }
@@ -91,7 +92,7 @@
     @Test
     public void createImageWithFailedAuth() throws AuthenticationException {
         authFailSetup();
-        when(imageExploratoryService.createImage(any(UserInfo.class), anyString(), anyString(), anyString(), anyString(), anyString()))
+        when(imageExploratoryService.createImage(any(UserInfo.class), anyString(), anyString(), anyString(), anyString()))
                 .thenReturn("someUuid");
         when(requestId.put(anyString(), anyString())).thenReturn("someUuid");
         final Response response = resources.getJerseyTest()
@@ -103,7 +104,7 @@
         assertEquals(HttpStatus.SC_ACCEPTED, response.getStatus());
         assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-        verify(imageExploratoryService).createImage(getUserInfo(), PROJECT, "someNotebookName", "someImageName", "someDescription", String.format(AUDIT_MESSAGE, "someImageName"));
+        verify(imageExploratoryService).createImage(getUserInfo(), PROJECT, "someNotebookName", "someImageName", "someDescription");
 
         verify(requestId).put(USER.toLowerCase(), "someUuid");
         verifyNoMoreInteractions(imageExploratoryService, requestId);
@@ -112,7 +113,7 @@
     @Test
     public void createImageWithException() {
         doThrow(new ResourceAlreadyExistException("Image with name is already exist"))
-                .when(imageExploratoryService).createImage(any(UserInfo.class), anyString(), anyString(), anyString(), anyString(), anyString());
+                .when(imageExploratoryService).createImage(any(UserInfo.class), anyString(), anyString(), anyString(), anyString());
         final Response response = resources.getJerseyTest()
                 .target("/infrastructure_provision/exploratory_environment/image")
                 .request()
@@ -122,55 +123,55 @@
         assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
         assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-        verify(imageExploratoryService).createImage(getUserInfo(), PROJECT, "someNotebookName", "someImageName", "someDescription", String.format(AUDIT_MESSAGE, "someImageName"));
+        verify(imageExploratoryService).createImage(getUserInfo(), PROJECT, "someNotebookName", "someImageName", "someDescription");
         verifyNoMoreInteractions(imageExploratoryService);
         verifyZeroInteractions(requestId);
     }
 
-    @Test
-    public void getImages() {
-        when(imageExploratoryService.getNotFailedImages(anyString(), anyString(), anyString(), anyString()))
-                .thenReturn(getImageList());
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/image")
-                .queryParam("docker_image", "someDockerImage")
-                .queryParam("project", "someProject")
-                .queryParam("endpoint", "someEndpoint")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .get();
+//    @Test
+//    public void getImages() {
+//        when(imageExploratoryService.getNotFailedImages(any(UserInfo.class), anyString(), anyString(), anyString()))
+//                .thenReturn(getImageList());
+//        final Response response = resources.getJerseyTest()
+//                .target("/infrastructure_provision/exploratory_environment/image")
+//                .queryParam("docker_image", "someDockerImage")
+//                .queryParam("project", "someProject")
+//                .queryParam("endpoint", "someEndpoint")
+//                .request()
+//                .header("Authorization", "Bearer " + TOKEN)
+//                .get();
+//
+//        assertEquals(HttpStatus.SC_OK, response.getStatus());
+//        assertEquals(getImageList(), response.readEntity(new GenericType<List<ImageInfoRecord>>() {
+//        }));
+//        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+//
+//        verify(imageExploratoryService).getNotFailedImages(getUserInfo(), "someDockerImage", "someProject", "someEndpoint");
+//        verifyNoMoreInteractions(imageExploratoryService);
+//    }
 
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals(getImageList(), response.readEntity(new GenericType<List<ImageInfoRecord>>() {
-        }));
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(imageExploratoryService).getNotFailedImages(USER.toLowerCase(), "someDockerImage", "someProject", "someEndpoint");
-        verifyNoMoreInteractions(imageExploratoryService);
-    }
-
-    @Test
-    public void getImagesWithFailedAuth() throws AuthenticationException {
-        authFailSetup();
-        when(imageExploratoryService.getNotFailedImages(anyString(), anyString(), anyString(), anyString()))
-                .thenReturn(getImageList());
-        final Response response = resources.getJerseyTest()
-                .target("/infrastructure_provision/exploratory_environment/image")
-                .queryParam("docker_image", "someDockerImage")
-                .queryParam("project", "someProject")
-                .queryParam("endpoint", "someEndpoint")
-                .request()
-                .header("Authorization", "Bearer " + TOKEN)
-                .get();
-
-        assertEquals(HttpStatus.SC_OK, response.getStatus());
-        assertEquals(getImageList(), response.readEntity(new GenericType<List<ImageInfoRecord>>() {
-        }));
-        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
-
-        verify(imageExploratoryService).getNotFailedImages(USER.toLowerCase(), "someDockerImage", "someProject", "someEndpoint");
-        verifyNoMoreInteractions(imageExploratoryService);
-    }
+//    @Test
+//    public void getImagesWithFailedAuth() throws AuthenticationException {
+//        authFailSetup();
+//        when(imageExploratoryService.getNotFailedImages(any(UserInfo.class), anyString(), anyString(), anyString()))
+//                .thenReturn(getImageList());
+//        final Response response = resources.getJerseyTest()
+//                .target("/infrastructure_provision/exploratory_environment/image")
+//                .queryParam("docker_image", "someDockerImage")
+//                .queryParam("project", "someProject")
+//                .queryParam("endpoint", "someEndpoint")
+//                .request()
+//                .header("Authorization", "Bearer " + TOKEN)
+//                .get();
+//
+//        assertEquals(HttpStatus.SC_OK, response.getStatus());
+//        assertEquals(getImageList(), response.readEntity(new GenericType<List<ImageInfoRecord>>() {
+//        }));
+//        assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
+//
+//        verify(imageExploratoryService).getNotFailedImages(getUserInfo(), "someDockerImage", "someProject", "someEndpoint");
+//        verifyNoMoreInteractions(imageExploratoryService);
+//    }
 
     @Test
     public void getImage() {
@@ -275,8 +276,24 @@
     }
 
     private List<ImageInfoRecord> getImageList() {
-        ImageInfoRecord imageInfoRecord = new ImageInfoRecord("someName", "someDescription", "someProject", "someEndpoint", "someUser", "someApp",
-                "someFullName", ImageStatus.CREATED);
+        ImageInfoRecord imageInfoRecord = new ImageInfoRecord("someName",
+                new Date(1580601722000L),
+                "someDescription",
+                "someProject",
+                "someEndpoint",
+                "someUser",
+                "someApp",
+                "someTemplateName",
+                "someInstance",
+                CloudProvider.AWS,
+                "someDockerImage",
+                "someFullName",
+                ImageStatus.ACTIVE,
+                null,
+                null,
+                null,
+                null,
+                null);
         return Collections.singletonList(imageInfoRecord);
     }
 }
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/ProjectServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/ProjectServiceImplTest.java
index b2fc3d6..a62e5cb 100644
--- a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/ProjectServiceImplTest.java
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/ProjectServiceImplTest.java
@@ -54,11 +54,7 @@
 import java.util.Set;
 
 import static org.junit.Assert.assertEquals;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyListOf;
-import static org.mockito.Matchers.anySet;
-import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.*;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/AuditServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/AuditServiceImplTest.java
index a7ad657..857e967 100644
--- a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/AuditServiceImplTest.java
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/AuditServiceImplTest.java
@@ -20,22 +20,25 @@
 package com.epam.datalab.backendapi.service.impl;
 
 import com.epam.datalab.backendapi.dao.AuditDAO;
-import com.epam.datalab.backendapi.domain.AuditActionEnum;
-import com.epam.datalab.backendapi.domain.AuditCreateDTO;
-import com.epam.datalab.backendapi.domain.AuditDTO;
-import com.epam.datalab.backendapi.domain.AuditResourceTypeEnum;
+import com.epam.datalab.backendapi.domain.*;
+import com.epam.datalab.backendapi.resources.dto.AuditFilter;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
 import org.mockito.runners.MockitoJUnitRunner;
 
+import java.time.LocalDate;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
+import java.util.StringJoiner;
 
-import static org.mockito.Matchers.eq;
-import static org.mockito.Matchers.refEq;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.*;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 @RunWith(MockitoJUnitRunner.class)
 public class AuditServiceImplTest {
@@ -83,6 +86,67 @@
         verify(auditDAO).getAudit(refEq(users), refEq(projects), refEq(resourceNames), refEq(resourceTypes), eq(dateStart), eq(dateEnd), eq(pageNumber), eq(pageSize));
     }
 
+    @Test
+    public void downloadAuditReport() {
+        when(auditDAO.aggregateAuditReport(any(AuditFilter.class))).thenReturn(getAuditReportLines());
+
+        String actualAuditReport = auditService.downloadAuditReport(getAuditFilter());
+        assertEquals("reports should be equal", prepareAuditReport(), actualAuditReport);
+
+        verify(auditDAO).aggregateAuditReport(getAuditFilter());
+    }
+
+    @Test
+    public void getAuditReport() {
+        when(auditDAO.aggregateAuditReport(any(AuditFilter.class))).thenReturn(getAuditReportLines());
+
+        AuditReport actualAuditReport = auditService.getAuditReport(getAuditFilter());
+        assertEquals("Audit Reports should be equal", getExpectedAuditReport(), actualAuditReport);
+
+        verify(auditDAO).aggregateAuditReport(getAuditFilter());
+    }
+
+    private String prepareAuditReport() {
+        StringBuilder auiditReport = new StringBuilder();
+        auiditReport.append("\"Available reporting period from: ").append("17-Mar-2022 ").append("to: ").append("20-Mar-2022").append("\"\n");
+        auiditReport.append(new StringJoiner(",").add("Date").add("User").add("Action").add("Project").add("Resource type").add("Resource\n"));
+        auiditReport.append(new StringJoiner(",").add("2022-03-20").add("test").add("LOG_IN").add("").add("").add("\n"));
+        auiditReport.append(new StringJoiner(",").add("2022-03-20").add("test").add("LOG_IN").add("").add("").add("\n"));
+        auiditReport.append(new StringJoiner(",").add("2022-03-19").add("test").add("LOG_IN").add("").add("").add("\n"));
+        auiditReport.append(new StringJoiner(",").add("2022-03-17").add("test").add("LOG_IN").add("").add("").add("\n"));
+
+        return auiditReport.toString();
+    }
+
+    private AuditReport getExpectedAuditReport() {
+        final LocalDate usageDateFrom = LocalDate.parse("2022-03-17");
+        final LocalDate usageDateTo = LocalDate.parse("2022-03-20");
+        return AuditReport.builder()
+                .name("Audit Report")
+                .usageDateFrom(usageDateFrom)
+                .usageDateTo(usageDateTo)
+                .reportLines(getAuditReportLines())
+                .build();
+    }
+
+    private List<AuditReportLine> getAuditReportLines() {
+        AuditReportLine line1 = AuditReportLine.builder().datalabId("123").user("test").action("LOG_IN").project("").resourceName("").resourceType("").timestamp(LocalDate.parse("2022-03-20")).build();
+        AuditReportLine line2 = AuditReportLine.builder().datalabId("124").user("test").action("LOG_IN").project("").resourceName("").resourceType("").timestamp(LocalDate.parse("2022-03-20")).build();
+        AuditReportLine line3 = AuditReportLine.builder().datalabId("126").user("test").action("LOG_IN").project("").resourceName("").resourceType("").timestamp(LocalDate.parse("2022-03-19")).build();
+        AuditReportLine line4 = AuditReportLine.builder().datalabId("126").user("test").action("LOG_IN").project("").resourceName("").resourceType("").timestamp(LocalDate.parse("2022-03-17")).build();
+
+        return Arrays.asList(line1, line2, line3, line4);
+    }
+
+    private AuditFilter getAuditFilter() {
+        AuditFilter auditFilter = new AuditFilter();
+        auditFilter.setDateStart("2022-03-17");
+        auditFilter.setDateEnd("2022-03-20");
+        auditFilter.setLocale("en-GB");
+
+        return auditFilter;
+    }
+
     private AuditDTO getAuditDTO() {
         return AuditDTO.builder()
                 .user(USER)
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/BillingServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/BillingServiceImplTest.java
index 672bc2e..cee2376 100644
--- a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/BillingServiceImplTest.java
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/BillingServiceImplTest.java
@@ -56,25 +56,15 @@
 
 import javax.ws.rs.core.GenericType;
 import java.time.LocalDate;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
-import java.util.StringJoiner;
+import java.util.*;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyListOf;
 import static org.mockito.Matchers.anySet;
 import static org.mockito.Matchers.anyString;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyNoMoreInteractions;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
 
 @RunWith(MockitoJUnitRunner.class)
 public class BillingServiceImplTest extends TestBase {
@@ -88,6 +78,7 @@
     private static final String IMAGE_NAME = "image_name";
     private static final String IMAGE_DESCRIPTION = "imageDescription";
     private static final String IMAGE_APPLICATION = "image_application";
+    private static final String TEMPLATE_NAME = "template_name";
     private static final String IMAGE_FULL_NAME = "imageFullName";
     private static final String BILLING_URL = "http://localhost:8088/api/billing";
     private static final String EXPLORATORY_NAME = "exploratoryName";
@@ -118,7 +109,7 @@
     private static final String COMPUTE_SLAVE_2_VOLUME_PRIMARY_ID = COMPUTE_ID + "-s2" + "-volume-primary";
     private static final String COMPUTE_SLAVE_2_VOLUME_SECONDARY_ID = COMPUTE_ID + "-s2" + "-volume-secondary";
     private static final String IMAGE_ID = SERVICE_BASE_NAME + "-" + PROJECT + "-" + ENDPOINT + "-" + IMAGE_APPLICATION + "-" + IMAGE_NAME;
-	private static final Integer BILLING_PORT = 8088;
+    private static final Integer BILLING_PORT = 8088;
 
     @Mock
     private SelfServiceApplicationConfiguration configuration;
@@ -154,7 +145,7 @@
         verify(billingDAO).aggregateBillingData(new BillingFilter());
         verify(projectService).get(PROJECT);
         verify(exploratoryService).getUserInstance(USER, PROJECT, EXPLORATORY_NAME);
-        verify(exploratoryService).getUserInstance(USER, PROJECT, EXPLORATORY_NAME, Boolean.TRUE);
+        verify(exploratoryService,times(2)).getUserInstance(USER, PROJECT, EXPLORATORY_NAME, Boolean.TRUE);
         verifyNoMoreInteractions(billingDAO);
     }
 
@@ -178,8 +169,7 @@
         when(exploratoryService.getUserInstance(anyString(), anyString(), anyString())).thenReturn(Optional.of(getUserInstanceDTO()));
         when(exploratoryService.getUserInstance(anyString(), anyString(), anyString(), anyBoolean())).thenReturn(Optional.of(getUserInstanceDTOWithCompute()));
 
-	    String actualBillingReport = billingService.downloadReport(getUserInfo(), new ExportBillingFilter(), "en-US");
-String get = getDownloadReport();
+        String actualBillingReport = billingService.downloadReport(getUserInfo(), new ExportBillingFilter(), "en-US");
         char[] chars1 = getDownloadReport().toCharArray();
         char[] chars2 = actualBillingReport.toCharArray();
         for (int i = 0; i < getDownloadReport().length(); i++) {
@@ -187,11 +177,11 @@
                 System.out.println(chars1[i] + " = " + chars2[i] + "  i = " + i);
         }
 
-	    assertEquals("reports should be equal", getDownloadReport(), actualBillingReport);
-	    verify(billingDAO).aggregateBillingData(new ExportBillingFilter());
-	    verify(projectService).get(PROJECT);
+        assertEquals("reports should be equal", getDownloadReport(), actualBillingReport);
+        verify(billingDAO).aggregateBillingData(new ExportBillingFilter());
+        verify(projectService).get(PROJECT);
         verify(exploratoryService).getUserInstance(USER, PROJECT, EXPLORATORY_NAME);
-        verify(exploratoryService).getUserInstance(USER, PROJECT, EXPLORATORY_NAME, Boolean.TRUE);
+        verify(exploratoryService,times(2)).getUserInstance(USER, PROJECT, EXPLORATORY_NAME, Boolean.TRUE);
         verifyNoMoreInteractions(billingDAO);
     }
 
@@ -219,9 +209,9 @@
 
     @Test
     public void updateGCPRemoteBillingData() {
-	    when(configuration.getServiceBaseName()).thenReturn(SERVICE_BASE_NAME);
-	    when(configuration.getBillingPort()).thenReturn(BILLING_PORT);
-	    when(configuration.getMaxSparkInstanceCount()).thenReturn(2);
+        when(configuration.getServiceBaseName()).thenReturn(SERVICE_BASE_NAME);
+        when(configuration.getBillingPort()).thenReturn(BILLING_PORT);
+        when(configuration.getMaxSparkInstanceCount()).thenReturn(2);
         when(endpointService.getEndpoints()).thenReturn(getGCPEndpointDTO());
         when(provisioningService.get(anyString(), anyString(), any(GenericType.class))).thenReturn(getBillingData());
         when(projectService.getProjects()).thenReturn(getProjectDTOs());
@@ -243,9 +233,9 @@
 
     @Test
     public void updateAWSRemoteBillingData() {
-	    when(configuration.getServiceBaseName()).thenReturn(SERVICE_BASE_NAME);
-	    when(configuration.getBillingPort()).thenReturn(BILLING_PORT);
-	    when(configuration.getMaxSparkInstanceCount()).thenReturn(2);
+        when(configuration.getServiceBaseName()).thenReturn(SERVICE_BASE_NAME);
+        when(configuration.getBillingPort()).thenReturn(BILLING_PORT);
+        when(configuration.getMaxSparkInstanceCount()).thenReturn(2);
         when(endpointService.getEndpoints()).thenReturn(getAWSEndpointDTO());
         when(provisioningService.get(anyString(), anyString(), any(GenericType.class))).thenReturn(getBillingData());
         when(projectService.getProjects()).thenReturn(getProjectDTOs());
@@ -267,9 +257,9 @@
 
     @Test
     public void updateAzureRemoteBillingData() {
-	    when(configuration.getServiceBaseName()).thenReturn(SERVICE_BASE_NAME);
-	    when(configuration.getBillingPort()).thenReturn(BILLING_PORT);
-	    when(configuration.getMaxSparkInstanceCount()).thenReturn(2);
+        when(configuration.getServiceBaseName()).thenReturn(SERVICE_BASE_NAME);
+        when(configuration.getBillingPort()).thenReturn(BILLING_PORT);
+        when(configuration.getMaxSparkInstanceCount()).thenReturn(2);
         when(endpointService.getEndpoints()).thenReturn(getAzureEndpointDTO());
         when(provisioningService.get(anyString(), anyString(), any(GenericType.class))).thenReturn(getBillingData());
         when(projectService.getProjects()).thenReturn(getProjectDTOs());
@@ -297,8 +287,8 @@
 
     @Test
     public void updateRemoteBillingDataWithException2() {
-	    when(configuration.getBillingPort()).thenReturn(BILLING_PORT);
-	    when(endpointService.getEndpoints()).thenReturn(getAWSEndpointDTO());
+        when(configuration.getBillingPort()).thenReturn(BILLING_PORT);
+        when(endpointService.getEndpoints()).thenReturn(getAWSEndpointDTO());
         when(provisioningService.get(anyString(), anyString(), any(GenericType.class))).thenThrow(new DatalabException("Exception message"));
 
         billingService.updateRemoteBillingData(getUserInfo());
@@ -558,7 +548,7 @@
                 .user(USER).project(PROJECT).endpoint(ENDPOINT).resourceName(EXPLORATORY_NAME).resourceType(BillingResourceType.VOLUME).build();
 
         BillingReportLine compute = BillingReportLine.builder().datalabId(COMPUTE_ID).usageDate(USAGE_DATE).application(ENDPOINT).user(USER).project(PROJECT)
-                .endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.COMPUTATIONAL).shape("3 x " + SHAPE).exploratoryName(EXPLORATORY_NAME).build();
+                .endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.COMPUTATIONAL).shape("Master: " + SHAPE + "Slave: 2 x " + SHAPE).exploratoryName(EXPLORATORY_NAME).build();
         BillingReportLine computePrimaryVolume = BillingReportLine.builder().datalabId(COMPUTE_VOLUME_PRIMARY_ID).usageDate(USAGE_DATE).application(ENDPOINT).user(USER)
                 .project(PROJECT).endpoint(ENDPOINT).resourceName(COMPUTE_NAME).resourceType(BillingResourceType.VOLUME).build();
         BillingReportLine computeSecondaryVolume = BillingReportLine.builder().datalabId(COMPUTE_VOLUME_SECONDARY_ID).usageDate(USAGE_DATE).application(ENDPOINT).user(USER)
@@ -655,7 +645,7 @@
                 .currency(CURRENCY).datalabId(EXPLORATORY_ID).product(PRODUCT).shape(SHAPE).user(USER).resourceType(BillingResourceType.EXPLORATORY).project(PROJECT)
                 .resourceName(EXPLORATORY_NAME).status(UserInstanceStatus.FAILED).build();
         BillingReportLine line3 = BillingReportLine.builder().usageDateFrom(LocalDate.parse("2020-03-01")).usageDateTo(LocalDate.parse("2020-04-01")).cost(1.0)
-                .currency(CURRENCY).datalabId(COMPUTE_ID).product(PRODUCT).shape(SHAPE).user(USER).resourceType(BillingResourceType.COMPUTATIONAL).project(PROJECT)
+                .currency(CURRENCY).datalabId(COMPUTE_ID).product(PRODUCT).shape("Master: " + 1 + " x " + SHAPE + " Slave: " + 2 + " x " + SHAPE).user(USER).resourceType(BillingResourceType.COMPUTATIONAL).project(PROJECT)
                 .resourceName(COMPUTE_NAME).exploratoryName(EXPLORATORY_NAME).status(UserInstanceStatus.CREATING).build();
         List<BillingReportLine> billingReportLines = Arrays.asList(line1, line2, line3);
 
@@ -685,18 +675,19 @@
     }
 
     private String getDownloadReport() {
-	    StringBuilder sb = new StringBuilder();
-	    sb.append("\"Service base name: ").append(SERVICE_BASE_NAME).append(". Available reporting period from: ").append("Jan 1, 2020")
-			    .append(" to: ").append("May 1, 2020").append("\"\r\n");
+        StringBuilder sb = new StringBuilder();
+        sb.append("\"Service base name: ").append(SERVICE_BASE_NAME).append(". Available reporting period from: ").append("Jan 1, 2020")
+                .append(" to: ").append("May 1, 2020").append("\"").append(System.lineSeparator());
 
-	    sb.append(new StringJoiner(",").add("DataLab ID").add("User").add("Project").add("DataLab Resource Type").add("Status").add("Shape").add("Product")
-			    .add("Cost\r\n").toString());
+        sb.append(new StringJoiner(",").add("DataLab ID").add("User").add("Project").add("DataLab Resource Type").add("Status").add("Shape").add("Product")
+                .add("Cost" + System.lineSeparator()));
 
-	    sb.append(new StringJoiner(",").add(EDGE_ID_1).add(USER).add(PROJECT).add("Edge").add("running").add(SHAPE).add(PRODUCT).add(1.999 + "\r\n"));
-	    sb.append(new StringJoiner(",").add(EXPLORATORY_ID).add(USER).add(PROJECT).add("Exploratory").add("failed").add(SHAPE).add(PRODUCT).add(1.0 + "\r\n"));
-	    sb.append(new StringJoiner(",").add(COMPUTE_ID).add(USER).add(PROJECT).add("Computational").add("creating").add(SHAPE).add(PRODUCT).add(1.0 + "\r\n"));
+        sb.append(new StringJoiner(",").add(EDGE_ID_1).add(USER).add(PROJECT).add("Edge").add("running").add(SHAPE).add(PRODUCT).add(1.999 + System.lineSeparator()));
+        sb.append(new StringJoiner(",").add(EXPLORATORY_ID).add(USER).add(PROJECT).add("Exploratory").add("failed").add(SHAPE).add(PRODUCT).add(1.0 + System.lineSeparator()));
+        sb.append(new StringJoiner(",").add(COMPUTE_ID).add(USER).add(PROJECT).add("Computational").add("creating").add("Master: " + 1 + " x " + SHAPE + " Slave: " + 2 + " x " + SHAPE).add(PRODUCT).add(1.0 + System.lineSeparator()));
 
-	    sb.append(",,,,,,,Total: 4.0 currency\r\n");
+        sb.append(",,,,,,,Total: 4.0 currency");
+        sb.append(System.lineSeparator());
 
         return sb.toString();
     }
@@ -738,16 +729,36 @@
         resource.setComputationalId(COMPUTE_ID);
         resource.setComputationalName(COMPUTE_NAME);
         resource.setImageName(DataEngineType.SPARK_STANDALONE.getName());
-        resource.setDataengineInstanceCount(3);
-        resource.setDataengineShape(SHAPE);
+        resource.setTotalInstanceCount(3);
+        resource.setMasterNodeShape(SHAPE);
+        resource.setSlaveNodeShape(SHAPE);
         resource.setStatus("creating");
+        resource.setTemplateName("template_name");
 
         return resource;
     }
 
     private List<ImageInfoRecord> getImageInfoRecords() {
         return Collections.singletonList(
-                new ImageInfoRecord(IMAGE_NAME, IMAGE_DESCRIPTION, PROJECT, ENDPOINT, USER, IMAGE_APPLICATION, IMAGE_FULL_NAME, ImageStatus.CREATED)
+                new ImageInfoRecord(
+                        IMAGE_NAME,
+                        new Date(),
+                        IMAGE_DESCRIPTION,
+                        PROJECT,
+                        ENDPOINT,
+                        USER,
+                        IMAGE_APPLICATION,
+                        TEMPLATE_NAME,
+                        EXPLORATORY_NAME,
+                        CloudProvider.GENERAL,
+                        "dockerImage",
+                        IMAGE_FULL_NAME,
+                        ImageStatus.ACTIVE,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null)
         );
     }
 }
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/BucketServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/BucketServiceImplTest.java
index d9c92fb..68bf2af 100644
--- a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/BucketServiceImplTest.java
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/BucketServiceImplTest.java
@@ -42,6 +42,7 @@
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
+import java.time.Instant;
 import java.time.LocalDate;
 import java.util.Collections;
 import java.util.List;
@@ -68,7 +69,7 @@
     private static final String BUCKET = "bucket";
     private static final String OBJECT = "object";
     private static final String SIZE = "size";
-    private static final long DATE = LocalDate.now().toEpochDay();
+    private static final long DATE = Instant.now().toEpochMilli();
     private static final String FOLDER = "folder/";
 
     @Mock
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/ImageExploratoryServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/ImageExploratoryServiceImplTest.java
index 78eb81f..f554ee1 100644
--- a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/ImageExploratoryServiceImplTest.java
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/ImageExploratoryServiceImplTest.java
@@ -25,6 +25,7 @@
 import com.epam.datalab.backendapi.dao.ImageExploratoryDAO;
 import com.epam.datalab.backendapi.domain.EndpointDTO;
 import com.epam.datalab.backendapi.domain.ProjectDTO;
+import com.epam.datalab.backendapi.resources.dto.ImageInfoDTO;
 import com.epam.datalab.backendapi.resources.dto.ImageInfoRecord;
 import com.epam.datalab.backendapi.service.EndpointService;
 import com.epam.datalab.backendapi.service.ProjectService;
@@ -53,6 +54,7 @@
 import org.mockito.runners.MockitoJUnitRunner;
 
 import java.util.Collections;
+import java.util.Date;
 import java.util.List;
 import java.util.Optional;
 
@@ -71,7 +73,6 @@
 
 @RunWith(MockitoJUnitRunner.class)
 public class ImageExploratoryServiceImplTest {
-    private final static String AUDIT_MESSAGE = "Image name: %s";
     private final String USER = "test";
     private final String TOKEN = "token";
     private final String EXPLORATORY_NAME = "expName";
@@ -130,7 +131,7 @@
 
         String imageName = "someImageName", imageDescription = "someDescription";
         String actualUuid = imageExploratoryService.createImage(userInfo, PROJECT, EXPLORATORY_NAME,
-                imageName, imageDescription, String.format(AUDIT_MESSAGE, imageName));
+                imageName, imageDescription);
         assertNotNull(actualUuid);
         assertEquals(expectedUuid, actualUuid);
 
@@ -154,7 +155,7 @@
         String imageName = "someImageName", imageDescription = "someDescription";
 
         try {
-            imageExploratoryService.createImage(userInfo, PROJECT, EXPLORATORY_NAME, imageName, imageDescription, String.format(AUDIT_MESSAGE, imageName));
+            imageExploratoryService.createImage(userInfo, PROJECT, EXPLORATORY_NAME, imageName, imageDescription);
         } catch (DatalabException e) {
             assertEquals("Running exploratory instance for user with name not found.", e.getMessage());
         }
@@ -171,7 +172,7 @@
         expectedException.expectMessage("Image with name someImageName is already exist");
 
         String imageName = "someImageName", imageDescription = "someDescription";
-        imageExploratoryService.createImage(userInfo, PROJECT, EXPLORATORY_NAME, imageName, imageDescription, String.format(AUDIT_MESSAGE, imageName));
+        imageExploratoryService.createImage(userInfo, PROJECT, EXPLORATORY_NAME, imageName, imageDescription);
     }
 
     @Test
@@ -190,7 +191,7 @@
 
         String imageName = "someImageName", imageDescription = "someDescription";
         try {
-            imageExploratoryService.createImage(userInfo, PROJECT, EXPLORATORY_NAME, imageName, imageDescription, String.format(AUDIT_MESSAGE, imageName));
+            imageExploratoryService.createImage(userInfo, PROJECT, EXPLORATORY_NAME, imageName, imageDescription);
         } catch (DatalabException e) {
             assertEquals("Cannot create instance of resource class", e.getMessage());
         }
@@ -257,22 +258,22 @@
         verifyNoMoreInteractions(exploratoryDAO, imageExploratoryDao);
     }
 
-    @Test
-    public void getCreatedImages() {
-        ImageInfoRecord imageInfoRecord = getImageInfoRecord();
-        List<ImageInfoRecord> expectedRecordList = Collections.singletonList(imageInfoRecord);
-        when(imageExploratoryDao.getImages(anyString(), anyString(), anyString(), anyString(), anyVararg()))
-                .thenReturn(expectedRecordList);
-
-        List<ImageInfoRecord> actualRecordList = imageExploratoryService.getNotFailedImages(USER,
-                "someImage", "someProject", "someEndpoint");
-        assertNotNull(actualRecordList);
-        assertEquals(1, actualRecordList.size());
-        assertEquals(expectedRecordList, actualRecordList);
-
-        verify(imageExploratoryDao).getImages(USER, "someImage", "someProject", "someEndpoint", ImageStatus.CREATED, ImageStatus.CREATING);
-        verifyNoMoreInteractions(imageExploratoryDao);
-    }
+//    @Test
+//    public void getCreatedImages() {
+//        ImageInfoDTO imageInfoDTO = getImageInfoDTO();
+//        List<ImageInfoDTO> expectedRecordList = Collections.singletonList(imageInfoDTO);
+//        when(imageExploratoryDao.getImages(anyString(), anyString(), anyString(), anyString(), anyVararg()))
+//                .thenReturn(expectedRecordList);
+//
+//        List<ImageInfoDTO> actualRecordList = imageExploratoryService.getNotFailedImages(getUserInfo(),
+//                "someImage", "someProject", "someEndpoint");
+//        assertNotNull(actualRecordList);
+//        assertEquals(1, actualRecordList.size());
+//        assertEquals(expectedRecordList, actualRecordList);
+//
+//        verify(imageExploratoryDao).getImages(USER, "someImage", "someProject", "someEndpoint", ImageStatus.ACTIVE, ImageStatus.CREATING);
+//        //verifyNoMoreInteractions(imageExploratoryDao);
+//    }
 
     @Test
     public void getImage() {
@@ -308,8 +309,24 @@
     }
 
     private ImageInfoRecord getImageInfoRecord() {
-        return new ImageInfoRecord("someName", "someDescription", "someProject", "someEndpoint", "someUser", "someApp",
-                "someFullName", ImageStatus.CREATED);
+        return new ImageInfoRecord("someName",
+                new Date(),
+                "someDescription",
+                "someProject",
+                "someEndpoint",
+                "someUser",
+                "someApp",
+                "someTemplate",
+                "someInstance",
+                CloudProvider.GENERAL,
+                "someDockerImage",
+                "someFullName",
+                ImageStatus.ACTIVE,
+                null,
+                null,
+                null,
+                null,
+                null);
     }
 
     private Image fetchImage() {
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/InfrastructureInfoServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/InfrastructureInfoServiceImplTest.java
index 683617a..93ecc38 100644
--- a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/InfrastructureInfoServiceImplTest.java
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/InfrastructureInfoServiceImplTest.java
@@ -255,6 +255,11 @@
                         .download(Boolean.TRUE)
                         .delete(Boolean.TRUE)
                         .build())
+                .connectedPlatforms(HealthStatusPageDTO.ConnectedPlatforms.builder()
+                        .view(Boolean.TRUE)
+                        .add(Boolean.TRUE)
+                        .disconnect(Boolean.TRUE)
+                        .build())
                 .build();
     }
 
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/SystemInfoServiceImplTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/SystemInfoServiceImplTest.java
index 388e01c..e3e01a3 100644
--- a/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/SystemInfoServiceImplTest.java
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/service/impl/SystemInfoServiceImplTest.java
@@ -90,7 +90,7 @@
         assertEquals(OS_FAMILY, systemInfo.getOsInfo().getFamily());
         assertEquals(PROCESSOR_MODEL, systemInfo.getProcessorInfo().getModel());
         assertEquals(AVAILABLE_MEMORY, systemInfo.getMemoryInfo().getAvailableMemory());
-        assertEquals(2, systemInfo.getDisksInfo().size());
+        assertEquals(1, systemInfo.getDisksInfo().size());
 
         verify(si).getOperatingSystem();
         verify(si).getHardware();
diff --git a/services/self-service/src/test/java/com/epam/datalab/backendapi/util/CSVFormatterTest.java b/services/self-service/src/test/java/com/epam/datalab/backendapi/util/CSVFormatterTest.java
index f4fe781..5098fe8 100644
--- a/services/self-service/src/test/java/com/epam/datalab/backendapi/util/CSVFormatterTest.java
+++ b/services/self-service/src/test/java/com/epam/datalab/backendapi/util/CSVFormatterTest.java
@@ -31,7 +31,7 @@
     @Test
     public void formatLine() {
         List<String> values = Arrays.asList("aaa", "bbb", "ccc", "aa", "bb", "cc", "a", "b", "c");
-        String expected = "aaa,bbb,ccc,aa,bb,cc,a,b,c\r\n";
+        String expected = "aaa,bbb,ccc,aa,bb,cc,a,b,c".concat(System.lineSeparator());
         String actual = CSVFormatter.formatLine(values, ',');
         assertEquals(expected, actual);
     }
@@ -39,7 +39,7 @@
     @Test
     public void formatLineWithCustomQuote() {
         List<String> values = Arrays.asList("aaa", "bbb", "ccc", "aa", "bb", "cc", "a", "b", "c");
-        String expected = "\"aaa\",\"bbb\",\"ccc\",\"aa\",\"bb\",\"cc\",\"a\",\"b\",\"c\"\r\n";
+        String expected = "\"aaa\",\"bbb\",\"ccc\",\"aa\",\"bb\",\"cc\",\"a\",\"b\",\"c\"".concat(System.lineSeparator());
         String actual = CSVFormatter.formatLine(values, ',', '"');
         assertEquals(expected, actual);
     }