Merge pull request #149 from apache/DLAB-176

[DLAB-176]: Fixed issue with devtools
diff --git a/infrastructure-provisioning/scripts/deploy_dlab.py b/infrastructure-provisioning/scripts/deploy_dlab.py
index 473e518..434c97b 100644
--- a/infrastructure-provisioning/scripts/deploy_dlab.py
+++ b/infrastructure-provisioning/scripts/deploy_dlab.py
@@ -103,18 +103,18 @@
 parser.add_argument('--azure_source_resource_group_name', type=str, default='', help='Azure source resource group')
 parser.add_argument('--gcp_project_id', type=str, default='', help='The project ID in Google Cloud Platform')
 parser.add_argument('--gcp_service_account_path', type=str, default='', help='The project ID in Google Cloud Platform')
-parser.add_argument('--dlab_id', type=str, default="'user:user:tag'", help='Column name in report file that contains '
+parser.add_argument('--dlab_id', type=str, default="'resource_tags_user_user_tag'", help='Column name in report file that contains '
                                                                            'dlab id tag')
-parser.add_argument('--usage_date', type=str, default='UsageStartDate', help='Column name in report file that contains '
+parser.add_argument('--usage_date', type=str, default='line_item_usage_start_date', help='Column name in report file that contains '
                                                                              'usage date tag')
-parser.add_argument('--product', type=str, default='ProductName', help='Column name in report file that contains '
+parser.add_argument('--product', type=str, default='product_product_name', help='Column name in report file that contains '
                                                                        'product name tag')
-parser.add_argument('--usage_type', type=str, default='UsageType', help='Column name in report file that contains '
+parser.add_argument('--usage_type', type=str, default='line_item_usage_type', help='Column name in report file that contains '
                                                                         'usage type tag')
-parser.add_argument('--usage', type=str, default='UsageQuantity', help='Column name in report file that contains '
+parser.add_argument('--usage', type=str, default='line_item_usage_amount', help='Column name in report file that contains '
                                                                        'usage tag')
-parser.add_argument('--cost', type=str, default='BlendedCost', help='Column name in report file that contains cost tag')
-parser.add_argument('--resource_id', type=str, default='ResourceId', help='Column name in report file that contains '
+parser.add_argument('--cost', type=str, default='line_item_blended_cost', 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 '
                                                                           'dlab resource id tag')
 parser.add_argument('--ldap_hostname', type=str, default='localhost', help='Ldap instance hostname')
 parser.add_argument('--ldap_dn', type=str, default='dc=example,dc=com',
@@ -123,7 +123,7 @@
 parser.add_argument('--ldap_service_username', type=str, default='cn=service-user', help='Ldap service user name')
 parser.add_argument('--ldap_service_password', type=str, default='service-user-password',
                     help='Ldap password for admin user')
-parser.add_argument('--tags', type=str, default='Operation,ItemDescription', help='Column name in report file that '
+parser.add_argument('--tags', type=str, default='line_item_operation,line_item_line_item_description', help='Column name in report file that '
                                                                                   'contains tags')
 parser.add_argument('--action', required=True, type=str, default='', choices=['build', 'deploy', 'create', 'terminate'],
                     help='Available options: build, deploy, create, terminate')
diff --git a/infrastructure-provisioning/src/base/scripts/install_user_key.py b/infrastructure-provisioning/src/base/scripts/install_user_key.py
index d026a0b..14246cb 100644
--- a/infrastructure-provisioning/src/base/scripts/install_user_key.py
+++ b/infrastructure-provisioning/src/base/scripts/install_user_key.py
@@ -47,7 +47,10 @@
             config.get('user_keydir'),
             config.get('user_keyname'))
         print(user_key)
-        key = open('{0}'.format(user_key)).read()
+        try:
+            key = config.get('user_key')
+        except KeyError:
+            key = open('{0}'.format(user_key)).read()
         sudo('echo "{0}" >> /home/{1}/.ssh/authorized_keys'.format(key, args.user))
     except:
         print('No user key')
diff --git a/infrastructure-provisioning/src/edge/fabfile.py b/infrastructure-provisioning/src/edge/fabfile.py
index 6700117..009f4e4 100644
--- a/infrastructure-provisioning/src/edge/fabfile.py
+++ b/infrastructure-provisioning/src/edge/fabfile.py
@@ -31,7 +31,7 @@
 
 
 def status():
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'], os.environ['request_id'])
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'], os.environ['request_id'])
     local_log_filepath = "/logs/edge/" + local_log_filename
     logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
                         level=logging.DEBUG,
@@ -45,47 +45,47 @@
         sys.exit(1)
 
 
-def run():
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
-                                               os.environ['request_id'])
-    local_log_filepath = "/logs/edge/" + local_log_filename
-    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
-                        level=logging.DEBUG,
-                        filename=local_log_filepath)
-
-    try:
-        local("~/scripts/{}.py".format('edge_prepare'))
-    except Exception as err:
-        traceback.print_exc()
-        append_result("Failed preparing Edge node.", str(err))
-        sys.exit(1)
-
-    try:
-        local("~/scripts/{}.py".format('edge_configure'))
-    except Exception as err:
-        traceback.print_exc()
-        append_result("Failed configuring Edge node.", str(err))
-        sys.exit(1)
+#def run():
+#    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+#                                               os.environ['request_id'])
+#    local_log_filepath = "/logs/edge/" + local_log_filename
+#    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+#                        level=logging.DEBUG,
+#                        filename=local_log_filepath)
+#
+#    try:
+#        local("~/scripts/{}.py".format('edge_prepare'))
+#    except Exception as err:
+#        traceback.print_exc()
+#        append_result("Failed preparing Edge node.", str(err))
+#        sys.exit(1)
+#
+#    try:
+#        local("~/scripts/{}.py".format('edge_configure'))
+#    except Exception as err:
+#        traceback.print_exc()
+#        append_result("Failed configuring Edge node.", str(err))
+#        sys.exit(1)
 
 
 # Main function for terminating EDGE node and exploratory environment if exists
-def terminate():
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'], os.environ['request_id'])
-    local_log_filepath = "/logs/edge/" + local_log_filename
-    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
-                        level=logging.DEBUG,
-                        filename=local_log_filepath)
-    try:
-        local("~/scripts/{}.py".format('edge_terminate'))
-    except Exception as err:
-        traceback.print_exc()
-        append_result("Failed terminating Edge node.", str(err))
-        sys.exit(1)
+#def terminate():
+#    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'], os.environ['request_id'])
+#    local_log_filepath = "/logs/edge/" + local_log_filename
+#    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+#                        level=logging.DEBUG,
+#                        filename=local_log_filepath)
+#    try:
+#        local("~/scripts/{}.py".format('edge_terminate'))
+#    except Exception as err:
+#       traceback.print_exc()
+#        append_result("Failed terminating Edge node.", str(err))
+#        sys.exit(1)
 
 
 # Main function for stopping EDGE node
 def stop():
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'], os.environ['request_id'])
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'], os.environ['request_id'])
     local_log_filepath = "/logs/edge/" + local_log_filename
     logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
                         level=logging.DEBUG,
@@ -98,9 +98,9 @@
         sys.exit(1)
 
 
-# Main function for stopping EDGE node
+# Main function for starting stoped EDGE node
 def start():
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'], os.environ['request_id'])
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'], os.environ['request_id'])
     local_log_filepath = "/logs/edge/" + local_log_filename
     logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
                         level=logging.DEBUG,
@@ -113,40 +113,39 @@
         sys.exit(1)
 
 
-def recreate():
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
-                                               os.environ['request_id'])
-    local_log_filepath = "/logs/edge/" + local_log_filename
-    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
-                        level=logging.DEBUG,
-                        filename=local_log_filepath)
+#def recreate():
+#    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+#                                               os.environ['request_id'])
+#    local_log_filepath = "/logs/edge/" + local_log_filename
+#    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+#                        level=logging.DEBUG,
+#                        filename=local_log_filepath)
+#
+#    try:
+#        local("~/scripts/{}.py".format('edge_prepare'))
+#    except Exception as err:
+#        traceback.print_exc()
+#        append_result("Failed preparing Edge node.", str(err))
+#        sys.exit(1)
+#
+#    try:
+#        local("~/scripts/{}.py".format('edge_configure'))
+#    except Exception as err:
+#        traceback.print_exc()
+#        append_result("Failed configuring Edge node.", str(err))
+#        sys.exit(1)
 
-    try:
-        local("~/scripts/{}.py".format('edge_prepare'))
-    except Exception as err:
-        traceback.print_exc()
-        append_result("Failed preparing Edge node.", str(err))
-        sys.exit(1)
-
-    try:
-        local("~/scripts/{}.py".format('edge_configure'))
-    except Exception as err:
-        traceback.print_exc()
-        append_result("Failed configuring Edge node.", str(err))
-        sys.exit(1)
-
-
-def reupload_key():
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
-                                               os.environ['request_id'])
-    local_log_filepath = "/logs/edge/" + local_log_filename
-    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
-                        level=logging.DEBUG,
-                        filename=local_log_filepath)
-
-    try:
-        local("~/scripts/{}.py".format('reupload_ssh_key'))
-    except Exception as err:
-        traceback.print_exc()
-        append_result("Failed to reupload key on Edge node.", str(err))
-        sys.exit(1)
\ No newline at end of file
+#def reupload_key():
+#    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'],
+#                                               os.environ['request_id'])
+#    local_log_filepath = "/logs/edge/" + local_log_filename
+#    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+#                        level=logging.DEBUG,
+#                        filename=local_log_filepath)
+#
+#    try:
+#        local("~/scripts/{}.py".format('reupload_ssh_key'))
+#    except Exception as err:
+#        traceback.print_exc()
+#        append_result("Failed to reupload key on Edge node.", str(err))
+#        sys.exit(1)
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/edge/scripts/configure_nginx_reverse_proxy.py b/infrastructure-provisioning/src/edge/scripts/configure_nginx_reverse_proxy.py
index 7772c50..b7123a3 100644
--- a/infrastructure-provisioning/src/edge/scripts/configure_nginx_reverse_proxy.py
+++ b/infrastructure-provisioning/src/edge/scripts/configure_nginx_reverse_proxy.py
@@ -56,8 +56,7 @@
         install_nginx_ldap(args.hostname, os.environ['reverse_proxy_nginx_version'],
                            os.environ['ldap_hostname'], os.environ['ldap_dn'],
                            os.environ['ldap_ou'], os.environ['ldap_service_password'],
-                           os.environ['ldap_service_username'], os.environ['{}_iam_user'.format(
-                           os.environ['conf_cloud_provider'])])
+                           os.environ['ldap_service_username'], os.environ['aws_iam_user'])
     except Exception as err:
         print("Failed install nginx reverse proxy: " + str(err))
         sys.exit(1)
diff --git a/infrastructure-provisioning/src/edge/templates/locations/dataengine-service.conf b/infrastructure-provisioning/src/edge/templates/locations/emr.conf
similarity index 100%
copy from infrastructure-provisioning/src/edge/templates/locations/dataengine-service.conf
copy to infrastructure-provisioning/src/edge/templates/locations/emr.conf
diff --git a/infrastructure-provisioning/src/edge/templates/nginx.conf b/infrastructure-provisioning/src/edge/templates/nginx.conf
index 6261f53..b952858 100644
--- a/infrastructure-provisioning/src/edge/templates/nginx.conf
+++ b/infrastructure-provisioning/src/edge/templates/nginx.conf
@@ -39,25 +39,19 @@
     sendfile            on;
     tcp_nopush          on;
     tcp_nodelay         on;
-    keepalive_timeout   100;
+    keepalive_timeout   65;
     types_hash_max_size 2048;
     proxy_read_timeout 86400s;
     proxy_send_timeout 86400s;
-    client_max_body_size 50M;
 
     include             /etc/nginx/mime.types;
     default_type        application/octet-stream;
 
-    auth_ldap_cache_enabled on;
-    auth_ldap_cache_expiration_time 10000;
-    auth_ldap_cache_size 1000;
-
     ldap_server ldap1 {
         url ldap://LDAP_IP:389/LDAP_DN?uid,mail?sub?(&(objectClass=posixAccount)(uid=LDAP_USERNAME));
         binddn "LDAP_SERVICE_USERNAME,LDAP_DN";
         binddn_passwd "LDAP_SERVICE_PASSWORD";
         require valid_user;
-        request_timeout 30s;
     }
 
     include /etc/nginx/conf.d/*.conf;
diff --git a/infrastructure-provisioning/src/general/api/check_inactivity.py b/infrastructure-provisioning/src/general/api/check_inactivity.py
index 5bacfee..31d7bb3 100644
--- a/infrastructure-provisioning/src/general/api/check_inactivity.py
+++ b/infrastructure-provisioning/src/general/api/check_inactivity.py
@@ -50,10 +50,10 @@
         reply['response']['result'] = {"error": "Failed to open result.json"}
 
     reply['response']['log'] = "/var/log/dlab/{0}/{0}_{1}_{2}.log".format(os.environ['conf_resource'],
-                                                                          os.environ['edge_user_name'],
+                                                                          os.environ['project_name'],
                                                                           os.environ['request_id'])
 
-    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['project_name'],
                                                os.environ['request_id']), 'w') as response_file:
         response_file.write(json.dumps(reply))
 
diff --git a/infrastructure-provisioning/src/general/api/configure.py b/infrastructure-provisioning/src/general/api/configure.py
index 9c917a4..4d6cc5f 100644
--- a/infrastructure-provisioning/src/general/api/configure.py
+++ b/infrastructure-provisioning/src/general/api/configure.py
@@ -49,10 +49,10 @@
     except:
         reply['response']['result'] = {"error": "Failed to open result.json"}
     reply['response']['log'] = "/var/log/dlab/{0}/{0}_{1}_{2}.log".format(os.environ['conf_resource'],
-                                                                          os.environ['edge_user_name'],
+                                                                          os.environ['project_name'],
                                                                           os.environ['request_id'])
 
-    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['project_name'],
                                                os.environ['request_id']), 'w') as response_file:
         response_file.write(json.dumps(reply))
 
diff --git a/infrastructure-provisioning/src/general/api/create.py b/infrastructure-provisioning/src/general/api/create.py
index 3be59d7..b2437b0 100644
--- a/infrastructure-provisioning/src/general/api/create.py
+++ b/infrastructure-provisioning/src/general/api/create.py
@@ -56,10 +56,10 @@
             response_file.write(json.dumps(reply))
     else:
         reply['response']['log'] = "/var/log/dlab/{0}/{0}_{1}_{2}.log".format(os.environ['conf_resource'],
-                                                                              os.environ['edge_user_name'],
+                                                                              os.environ['project_name'],
                                                                               os.environ['request_id'])
 
-        with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+        with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['project_name'],
                                                    os.environ['request_id']), 'w') as response_file:
             response_file.write(json.dumps(reply))
 
diff --git a/infrastructure-provisioning/src/general/api/create_image.py b/infrastructure-provisioning/src/general/api/create_image.py
index 7e96c5d..425cf26 100644
--- a/infrastructure-provisioning/src/general/api/create_image.py
+++ b/infrastructure-provisioning/src/general/api/create_image.py
@@ -50,10 +50,10 @@
         reply['response']['result'] = {"error": "Failed to open result.json"}
 
     reply['response']['log'] = "/var/log/dlab/{0}/{0}_{1}_{2}.log".format(os.environ['conf_resource'],
-                                                                          os.environ['edge_user_name'],
+                                                                          os.environ['project_name'],
                                                                           os.environ['request_id'])
 
-    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['project_name'],
                                                os.environ['request_id']), 'w') as response_file:
         response_file.write(json.dumps(reply))
 
diff --git a/infrastructure-provisioning/src/general/api/git_creds.py b/infrastructure-provisioning/src/general/api/git_creds.py
index 1e001e7..4edd370 100644
--- a/infrastructure-provisioning/src/general/api/git_creds.py
+++ b/infrastructure-provisioning/src/general/api/git_creds.py
@@ -50,10 +50,10 @@
         reply['response']['result'] = {"error": "Failed to open result.json"}
 
     reply['response']['log'] = "/var/log/dlab/{0}/{0}_{1}_{2}.log".format(os.environ['conf_resource'],
-                                                                          os.environ['edge_user_name'],
+                                                                          os.environ['project_name'],
                                                                           os.environ['request_id'])
 
-    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['project_name'],
                                                os.environ['request_id']), 'w') as response_file:
         response_file.write(json.dumps(reply))
 
diff --git a/infrastructure-provisioning/src/general/api/install_libs.py b/infrastructure-provisioning/src/general/api/install_libs.py
index abbe252..21489a9 100644
--- a/infrastructure-provisioning/src/general/api/install_libs.py
+++ b/infrastructure-provisioning/src/general/api/install_libs.py
@@ -50,10 +50,10 @@
         reply['response']['result'] = {"error": "Failed to open result.json"}
 
     reply['response']['log'] = "/var/log/dlab/{0}/{0}_{1}_{2}.log".format(os.environ['conf_resource'],
-                                                                          os.environ['edge_user_name'],
+                                                                          os.environ['project_name'],
                                                                           os.environ['request_id'])
 
-    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['project_name'],
                                                os.environ['request_id']), 'w') as response_file:
         response_file.write(json.dumps(reply))
 
diff --git a/infrastructure-provisioning/src/general/api/list_libs.py b/infrastructure-provisioning/src/general/api/list_libs.py
index e5e7c41..d7c97a9 100644
--- a/infrastructure-provisioning/src/general/api/list_libs.py
+++ b/infrastructure-provisioning/src/general/api/list_libs.py
@@ -50,21 +50,21 @@
         reply['response']['result'] = {"error": "Failed to open result.json"}
 
     reply['response']['log'] = "/var/log/dlab/{0}/{0}_{1}_{2}.log".format(os.environ['conf_resource'],
-                                                                          os.environ['edge_user_name'],
+                                                                          os.environ['project_name'],
                                                                           os.environ['request_id'])
 
-    reply['response']['result']['file'] = "/opt/dlab/tmp/result/{0}_{1}_{2}_all_pkgs.json".format(os.environ['edge_user_name'],
+    reply['response']['result']['file'] = "/opt/dlab/tmp/result/{0}_{1}_{2}_all_pkgs.json".format(os.environ['project_name'],
                                                                                                   os.environ['application'],
                                                                                                   os.environ['request_id'])
 
-    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['project_name'],
                                                os.environ['request_id']), 'w') as response_file:
         response_file.write(json.dumps(reply))
 
     try:
         with open("/root/all_pkgs.json") as f:
             tmp = json.loads(f.read())
-            with open("/response/{}_{}_{}_all_pkgs.json".format(os.environ['edge_user_name'],
+            with open("/response/{}_{}_{}_all_pkgs.json".format(os.environ['project_name'],
                                                                 os.environ['application'],
                                                                 os.environ['request_id']), 'w') as response_file:
                 response_file.write(json.dumps(tmp))
diff --git a/infrastructure-provisioning/src/general/api/reconfigure_spark.py b/infrastructure-provisioning/src/general/api/reconfigure_spark.py
index b7458dc..09139ca 100644
--- a/infrastructure-provisioning/src/general/api/reconfigure_spark.py
+++ b/infrastructure-provisioning/src/general/api/reconfigure_spark.py
@@ -50,10 +50,10 @@
         reply['response']['result'] = {"error": "Failed to open result.json"}
 
     reply['response']['log'] = "/var/log/dlab/{0}/{0}_{1}_{2}.log".format(os.environ['conf_resource'],
-                                                                          os.environ['edge_user_name'],
+                                                                          os.environ['project_name'],
                                                                           os.environ['request_id'])
 
-    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['project_name'],
                                                os.environ['request_id']), 'w') as response_file:
         response_file.write(json.dumps(reply))
 
diff --git a/infrastructure-provisioning/src/general/api/recreate.py b/infrastructure-provisioning/src/general/api/recreate.py
index 4d7d3fc..e91e579 100644
--- a/infrastructure-provisioning/src/general/api/recreate.py
+++ b/infrastructure-provisioning/src/general/api/recreate.py
@@ -56,10 +56,10 @@
             response_file.write(json.dumps(reply))
     else:
         reply['response']['log'] = "/var/log/dlab/{0}/{0}_{1}_{2}.log".format(os.environ['conf_resource'],
-                                                                              os.environ['edge_user_name'],
+                                                                              os.environ['project_name'],
                                                                               os.environ['request_id'])
 
-        with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+        with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['project_name'],
                                                    os.environ['request_id']), 'w') as response_file:
             response_file.write(json.dumps(reply))
 
diff --git a/infrastructure-provisioning/src/general/api/reupload_key.py b/infrastructure-provisioning/src/general/api/reupload_key.py
index 771abae..d4af110 100644
--- a/infrastructure-provisioning/src/general/api/reupload_key.py
+++ b/infrastructure-provisioning/src/general/api/reupload_key.py
@@ -52,10 +52,10 @@
 
 
     log = "/var/log/dlab/edge/{0}_{1}_{2}.log".format(os.environ['conf_resource'],
-                                                                          os.environ['edge_user_name'],
+                                                                          os.environ['project_name'],
                                                                           os.environ['request_id'])
     try:
-        with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+        with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['project_name'],
                                                    os.environ['request_id']), 'w') as response_file:
             response_file.write(json.dumps(reply))
             print(json.dumps(reply))
diff --git a/infrastructure-provisioning/src/general/api/start.py b/infrastructure-provisioning/src/general/api/start.py
index 3358588..469d5a6 100644
--- a/infrastructure-provisioning/src/general/api/start.py
+++ b/infrastructure-provisioning/src/general/api/start.py
@@ -49,10 +49,10 @@
     except:
         reply['response']['result'] = {"error": "Failed to open result.json"}
     reply['response']['log'] = "/var/log/dlab/{0}/{0}_{1}_{2}.log".format(os.environ['conf_resource'],
-                                                                          os.environ['edge_user_name'],
+                                                                          os.environ['project_name'],
                                                                           os.environ['request_id'])
 
-    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['project_name'],
                                                os.environ['request_id']), 'w') as response_file:
         response_file.write(json.dumps(reply))
 
diff --git a/infrastructure-provisioning/src/general/api/status.py b/infrastructure-provisioning/src/general/api/status.py
index 0b007b9..e289c9c 100644
--- a/infrastructure-provisioning/src/general/api/status.py
+++ b/infrastructure-provisioning/src/general/api/status.py
@@ -49,10 +49,10 @@
     except:
         reply['response']['result'] = {"error": "Failed to open result.json"}
     reply['response']['log'] = "/var/log/dlab/{0}/{0}_{1}_{2}.log".format(os.environ['conf_resource'],
-                                                                          os.environ['edge_user_name'],
+                                                                          os.environ['project_name'],
                                                                           os.environ['request_id'])
 
-    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['project_name'],
                                                os.environ['request_id']), 'w') as response_file:
         response_file.write(json.dumps(reply))
 
diff --git a/infrastructure-provisioning/src/general/api/stop.py b/infrastructure-provisioning/src/general/api/stop.py
index a92c674..8dc2a11 100644
--- a/infrastructure-provisioning/src/general/api/stop.py
+++ b/infrastructure-provisioning/src/general/api/stop.py
@@ -50,10 +50,10 @@
         reply['response']['result'] = {"error": "Failed to open result.json"}
 
     reply['response']['log'] = "/var/log/dlab/{0}/{0}_{1}_{2}.log".format(os.environ['conf_resource'],
-                                                                          os.environ['edge_user_name'],
+                                                                          os.environ['project_name'],
                                                                           os.environ['request_id'])
 
-    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['project_name'],
                                                os.environ['request_id']), 'w') as response_file:
         response_file.write(json.dumps(reply))
 
diff --git a/infrastructure-provisioning/src/general/api/terminate.py b/infrastructure-provisioning/src/general/api/terminate.py
index 783e366..933af27 100644
--- a/infrastructure-provisioning/src/general/api/terminate.py
+++ b/infrastructure-provisioning/src/general/api/terminate.py
@@ -56,10 +56,10 @@
             response_file.write(json.dumps(reply))
     else:
         reply['response']['log'] = "/var/log/dlab/{0}/{0}_{1}_{2}.log".format(os.environ['conf_resource'],
-                                                                              os.environ['edge_user_name'],
+                                                                              os.environ['project_name'],
                                                                               os.environ['request_id'])
 
-        with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+        with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['project_name'],
                                                    os.environ['request_id']), 'w') as response_file:
             response_file.write(json.dumps(reply))
 
diff --git a/infrastructure-provisioning/src/general/api/terminate_image.py b/infrastructure-provisioning/src/general/api/terminate_image.py
index b24462d..0700686 100644
--- a/infrastructure-provisioning/src/general/api/terminate_image.py
+++ b/infrastructure-provisioning/src/general/api/terminate_image.py
@@ -50,10 +50,10 @@
         reply['response']['result'] = {"error": "Failed to open result.json"}
 
     reply['response']['log'] = "/var/log/dlab/{0}/{0}_{1}_{2}.log".format(os.environ['conf_resource'],
-                                                                          os.environ['edge_user_name'],
+                                                                          os.environ['project_name'],
                                                                           os.environ['request_id'])
 
-    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    with open("/response/{}_{}_{}.json".format(os.environ['conf_resource'], os.environ['project_name'],
                                                os.environ['request_id']), 'w') as response_file:
         response_file.write(json.dumps(reply))
 
diff --git a/infrastructure-provisioning/src/general/files/aws/base_Dockerfile b/infrastructure-provisioning/src/general/files/aws/base_Dockerfile
index a86d64f..f3ef362 100644
--- a/infrastructure-provisioning/src/general/files/aws/base_Dockerfile
+++ b/infrastructure-provisioning/src/general/files/aws/base_Dockerfile
@@ -43,6 +43,7 @@
 # Configuring log directories
 RUN mkdir -p /response; chmod a+rwx /response && \
     mkdir -p /logs/ssn; chmod a+rwx /logs/ssn && \
+    mkdir -p /logs/project; chmod a+rwx /logs/project && \
     mkdir -p /logs/edge; chmod a+rwx /logs/edge && \
     mkdir -p /logs/notebook; chmod a+rwx /logs/notebook && \
     mkdir -p /logs/dataengine; chmod a+rwx /logs/dataengine && \
@@ -69,7 +70,7 @@
 COPY ${SRC_PATH}general/lib/os/fab.py /usr/lib/python2.7/dlab/fab.py
 COPY ${SRC_PATH}general/files/os/${OS}/sources.list /root/files/
 COPY ${SRC_PATH}general/files/os/ivysettings.xml /root/templates/
-COPY ${SRC_PATH}edge/templates/locations/ /root/locations/
+COPY ${SRC_PATH}project/templates/locations/ /root/locations/
 
 RUN chmod a+x /root/*.py && \
     chmod a+x /root/scripts/* && \
diff --git a/infrastructure-provisioning/src/general/files/aws/edge_description.json b/infrastructure-provisioning/src/general/files/aws/edge_description.json
index 3f9a65c..d209f72 100644
--- a/infrastructure-provisioning/src/general/files/aws/edge_description.json
+++ b/infrastructure-provisioning/src/general/files/aws/edge_description.json
@@ -1,4 +1,4 @@
 {
-  "template_name": "Crete exploratory environment.",
-  "description": "Create user subnet, bucket and edge node for access."
+  "template_name": "Edge node service.",
+  "description": "Edge node start/stop/status."
 }
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/general/files/aws/project_Dockerfile b/infrastructure-provisioning/src/general/files/aws/project_Dockerfile
new file mode 100644
index 0000000..4fa38da
--- /dev/null
+++ b/infrastructure-provisioning/src/general/files/aws/project_Dockerfile
@@ -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.
+#
+# ******************************************************************************
+
+
+FROM docker.dlab-base:latest
+
+ARG OS
+
+COPY project/ /root/
+COPY general/scripts/aws/project_* /root/scripts/
+COPY general/scripts/aws/edge_* /root/scripts/
+COPY general/lib/os/${OS}/edge_lib.py /usr/lib/python2.7/dlab/edge_lib.py
+COPY general/templates/aws/edge_s3_policy.json /root/templates/edge_s3_policy.json
+
+RUN chmod a+x /root/fabfile.py; \
+    chmod a+x /root/scripts/*
diff --git a/infrastructure-provisioning/src/general/files/aws/project_description.json b/infrastructure-provisioning/src/general/files/aws/project_description.json
new file mode 100644
index 0000000..fff7b0b
--- /dev/null
+++ b/infrastructure-provisioning/src/general/files/aws/project_description.json
@@ -0,0 +1,4 @@
+{
+  "template_name": "Crete project environment.",
+  "description": "Create user subnet."
+}
\ No newline at end of file
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 6bae640..31f3095 100644
--- a/infrastructure-provisioning/src/general/lib/os/debian/edge_lib.py
+++ b/infrastructure-provisioning/src/general/lib/os/debian/edge_lib.py
@@ -36,7 +36,7 @@
             put(template_file, '/tmp/squid.conf')
             sudo('\cp /tmp/squid.conf /etc/squid/squid.conf')
             sudo('sed -i "s|PROXY_SUBNET|{}|g" /etc/squid/squid.conf'.format(proxy_subnet))
-            sudo('sed -i "s|EDGE_USER_NAME|{}|g" /etc/squid/squid.conf'.format(config['edge_user_name']))
+            sudo('sed -i "s|EDGE_USER_NAME|{}|g" /etc/squid/squid.conf'.format(config['project_name']))
             sudo('sed -i "s|LDAP_HOST|{}|g" /etc/squid/squid.conf'.format(config['ldap_host']))
             sudo('sed -i "s|LDAP_DN|{}|g" /etc/squid/squid.conf'.format(config['ldap_dn']))
             sudo('sed -i "s|LDAP_SERVICE_USERNAME|{}|g" /etc/squid/squid.conf'.format(config['ldap_user']))
@@ -58,8 +58,7 @@
         sys.exit(1)
 
 
-def install_nginx_ldap(edge_ip, nginx_version, ldap_ip, ldap_dn, ldap_ou, ldap_service_pass, ldap_service_username,
-                       ldap_user):
+def install_nginx_ldap(edge_ip, nginx_version, ldap_ip, ldap_dn, ldap_ou, ldap_service_pass, ldap_service_username):
     try:
         if not os.path.exists('/tmp/nginx_installed'):
             sudo('apt-get install -y wget')
@@ -91,7 +90,6 @@
             sudo('sed -i \'s/LDAP_OU/{}/g\' /opt/dlab/templates/nginx.conf'.format(ldap_ou))
             sudo('sed -i \'s/LDAP_SERVICE_PASSWORD/{}/g\' /opt/dlab/templates/nginx.conf'.format(ldap_service_pass))
             sudo('sed -i \'s/LDAP_SERVICE_USERNAME/{}/g\' /opt/dlab/templates/nginx.conf'.format(ldap_service_username))
-            sudo('sed -i \'s/LDAP_USERNAME/{}/g\' /opt/dlab/templates/nginx.conf'.format(ldap_user))
             sudo('sed -i \'s/EDGE_IP/{}/g\' /opt/dlab/templates/conf.d/proxy.conf'.format(edge_ip))
             sudo('cp /opt/dlab/templates/nginx.conf /etc/nginx/')
             sudo('mkdir /etc/nginx/conf.d')
diff --git a/infrastructure-provisioning/src/general/lib/os/redhat/edge_lib.py b/infrastructure-provisioning/src/general/lib/os/redhat/edge_lib.py
index 1b92581..1a6f773 100644
--- a/infrastructure-provisioning/src/general/lib/os/redhat/edge_lib.py
+++ b/infrastructure-provisioning/src/general/lib/os/redhat/edge_lib.py
@@ -36,7 +36,7 @@
             put(template_file, '/tmp/squid.conf')
             sudo('\cp /tmp/squid.conf /etc/squid/squid.conf')
             sudo('sed -i "s|PROXY_SUBNET|{}|g" /etc/squid/squid.conf'.format(proxy_subnet))
-            sudo('sed -i "s|EDGE_USER_NAME|{}|g" /etc/squid/squid.conf'.format(config['edge_user_name']))
+            sudo('sed -i "s|EDGE_USER_NAME|{}|g" /etc/squid/squid.conf'.format(config['project_name']))
             sudo('sed -i "s|LDAP_HOST|{}|g" /etc/squid/squid.conf'.format(config['ldap_host']))
             sudo('sed -i "s|LDAP_DN|{}|g" /etc/squid/squid.conf'.format(config['ldap_dn']))
             sudo('sed -i "s|LDAP_SERVICE_USERNAME|{}|g" /etc/squid/squid.conf'.format(config['ldap_user']))
@@ -58,8 +58,7 @@
         sys.exit(1)
 
 
-def install_nginx_ldap(edge_ip, nginx_version, ldap_ip, ldap_dn, ldap_ou, ldap_service_pass, ldap_service_username,
-                       ldap_user):
+def install_nginx_ldap(edge_ip, nginx_version, ldap_ip, ldap_dn, ldap_ou, ldap_service_pass, ldap_service_username):
     try:
         if not os.path.exists('/tmp/nginx_installed'):
             sudo('yum install -y wget')
@@ -97,7 +96,6 @@
             sudo('sed -i \'s/LDAP_OU/{}/g\' /opt/dlab/templates/nginx.conf'.format(ldap_ou))
             sudo('sed -i \'s/LDAP_SERVICE_PASSWORD/{}/g\' /opt/dlab/templates/nginx.conf'.format(ldap_service_pass))
             sudo('sed -i \'s/LDAP_SERVICE_USERNAME/{}/g\' /opt/dlab/templates/nginx.conf'.format(ldap_service_username))
-            sudo('sed -i \'s/LDAP_USERNAME/{}/g\' /opt/dlab/templates/nginx.conf'.format(ldap_user))
             sudo('sed -i \'s/EDGE_IP/{}/g\' /opt/dlab/templates/conf.d/proxy.conf'.format(edge_ip))
             sudo('cp /opt/dlab/templates/nginx.conf /etc/nginx/')
             sudo('mkdir /etc/nginx/conf.d')
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 d50b0ba..3d418c1 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
@@ -34,18 +34,18 @@
         image_conf = dict()
         create_aws_config_files()
         image_conf['service_base_name'] = os.environ['conf_service_base_name']
-        image_conf['user_name'] = os.environ['edge_user_name']
+        image_conf['project_tag'] = os.environ['project_name']
         image_conf['instance_name'] = os.environ['notebook_instance_name']
         image_conf['instance_tag'] = '{}-Tag'.format(image_conf['service_base_name'])
         image_conf['application'] = os.environ['application']
         image_conf['image_name'] = os.environ['notebook_image_name'].lower().replace('_', '-')
         image_conf['full_image_name'] = '{}-{}-{}-{}'.format(image_conf['service_base_name'],
-                                                             image_conf['user_name'],
+                                                             image_conf['project_tag'],
                                                              image_conf['application'],
                                                              image_conf['image_name']).lower()
         image_conf['tags'] = {"Name": image_conf['service_base_name'],
                               "SBN": image_conf['service_base_name'],
-                              "User": image_conf['user_name'],
+                              "Project": image_conf['project_tag'],
                               "Image": image_conf['image_name'],
                               "FIN": image_conf['full_image_name'],
                               os.environ['conf_billing_tag_key']: os.environ['conf_billing_tag_value']}
@@ -61,7 +61,7 @@
             with open("/root/result.json", 'w') as result:
                 res = {"notebook_image_name": image_conf['image_name'],
                        "full_image_name": image_conf['full_image_name'],
-                       "user_name": image_conf['user_name'],
+                       "project_tag": image_conf['project_tag'],
                        "application": image_conf['application'],
                        "status": "created",
                        "Action": "Create image from notebook"}
diff --git a/infrastructure-provisioning/src/general/scripts/aws/common_notebook_configure_dataengine-service.py b/infrastructure-provisioning/src/general/scripts/aws/common_notebook_configure_dataengine-service.py
index 413ccbf..106f062 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/common_notebook_configure_dataengine-service.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/common_notebook_configure_dataengine-service.py
@@ -32,7 +32,7 @@
 
 
 if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -53,7 +53,7 @@
                                                              notebook_config['notebook_name']).get('Private')
     notebook_config['key_path'] = os.environ['conf_key_dir'] + '/' + os.environ['conf_key_name'] + '.pem'
     notebook_config['cluster_id'] = get_emr_id_by_name(notebook_config['cluster_name'])
-    edge_instance_name = os.environ['conf_service_base_name'] + "-" + os.environ['edge_user_name'] + '-edge'
+    edge_instance_name = os.environ['conf_service_base_name'] + "-" + os.environ['project_name'] + '-edge'
     edge_instance_hostname = get_instance_hostname(notebook_config['tag_name'], edge_instance_name)
     if os.environ['application'] == 'deeplearning':
         application = 'jupyter'
@@ -63,10 +63,10 @@
     try:
         logging.info('[INSTALLING KERNELS INTO SPECIFIED NOTEBOOK]')
         print('[INSTALLING KERNELS INTO SPECIFIED NOTEBOOK]')
-        params = "--bucket {} --cluster_name {} --emr_version {} --keyfile {} --notebook_ip {} --region {} --emr_excluded_spark_properties {} --edge_user_name {} --os_user {}  --edge_hostname {} --proxy_port {} --scala_version {} --application {} --pip_mirror {}" \
+        params = "--bucket {} --cluster_name {} --emr_version {} --keyfile {} --notebook_ip {} --region {} --emr_excluded_spark_properties {} --project_name {} --os_user {}  --edge_hostname {} --proxy_port {} --scala_version {} --application {} --pip_mirror {}" \
             .format(notebook_config['bucket_name'], notebook_config['cluster_name'], os.environ['emr_version'],
                     notebook_config['key_path'], notebook_config['notebook_ip'], os.environ['aws_region'],
-                    os.environ['emr_excluded_spark_properties'], os.environ['edge_user_name'],
+                    os.environ['emr_excluded_spark_properties'], os.environ['project_name'],
                     os.environ['conf_os_user'], edge_instance_hostname, '3128', os.environ['notebook_scala_version'],
                     os.environ['application'], os.environ['conf_pypi_mirror'])
         try:
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 9610083..8e969c2 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
@@ -32,7 +32,7 @@
 
 
 if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -55,8 +55,8 @@
         notebook_config['service_base_name'] = os.environ['conf_service_base_name']
         notebook_config['region'] = os.environ['aws_region']
         notebook_config['tag_name'] = notebook_config['service_base_name'] + '-Tag'
-        notebook_config['user_name'] = os.environ['edge_user_name']
-        notebook_config['cluster_name'] = notebook_config['service_base_name'] + '-' + notebook_config['user_name'] + \
+        notebook_config['project_tag'] = os.environ['project_name']
+        notebook_config['cluster_name'] = notebook_config['service_base_name'] + '-' + notebook_config['project_tag'] + \
                                           '-de-' + notebook_config['exploratory_name'] + '-' + \
                                           notebook_config['computational_name']
         notebook_config['master_node_name'] = notebook_config['cluster_name'] + '-m'
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 eecfae6..4ae9e17 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/common_prepare_notebook.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/common_prepare_notebook.py
@@ -36,7 +36,7 @@
 
 if __name__ == "__main__":
     instance_class = 'notebook'
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -46,7 +46,7 @@
     # generating variables dictionary
     create_aws_config_files()
     edge_status = get_instance_status(os.environ['conf_service_base_name'] + '-Tag',
-        os.environ['conf_service_base_name'] + '-' + os.environ['edge_user_name'] + '-edge')
+        os.environ['conf_service_base_name'] + '-' + os.environ['project_name'] + '-edge')
     if edge_status != 'running':
         logging.info('ERROR: Edge node is unavailable! Aborting...')
         print('ERROR: Edge node is unavailable! Aborting...')
@@ -64,13 +64,13 @@
     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'],
-                                                               os.environ['edge_user_name'],
+                                                               os.environ['project_name'],
                                                                notebook_config['exploratory_name'], args.uuid)
     notebook_config['primary_disk_size'] = (lambda x: '30' if x == 'deeplearning' else '12')(os.environ['application'])
     notebook_config['role_profile_name'] = '{}-{}-nb-de-Profile' \
-        .format(notebook_config['service_base_name'].lower().replace('-', '_'), os.environ['edge_user_name'])
+        .format(notebook_config['service_base_name'].lower().replace('-', '_'), os.environ['project_name'])
     notebook_config['security_group_name'] = '{}-{}-nb-SG'.format(notebook_config['service_base_name'],
-                                                                  os.environ['edge_user_name'])
+                                                                  os.environ['project_name'])
     notebook_config['tag_name'] = '{}-Tag'.format(notebook_config['service_base_name'])
 
     notebook_config['expected_image_name'] = '{}-{}-notebook-image'.format(notebook_config['service_base_name'],
@@ -88,7 +88,7 @@
         print('No pre-configured image found. Using default one: {}'.format(notebook_config['ami_id']))
     
     tag = {"Key": notebook_config['tag_name'],
-           "Value": "{}-{}-subnet".format(notebook_config['service_base_name'], os.environ['edge_user_name'])}
+           "Value": "{}-{}-subnet".format(notebook_config['service_base_name'], os.environ['project_name'])}
     notebook_config['subnet_cidr'] = get_subnet_by_tag(tag)
     keyfile_name = "{}{}.pem".format(os.environ['conf_key_dir'], os.environ['conf_key_name'])
 
@@ -108,6 +108,9 @@
                     os.environ['notebook_disk_size'], notebook_config['primary_disk_size'])
         try:
             local("~/scripts/{}.py {}".format('common_create_instance', params))
+            notebook_instance = get_instance_by_name(notebook_config['tag_name'], notebook_config['instance_name'])
+            project_tag = {"Key": 'project_tag', "Value": os.environ['project_name']}
+            create_tag(notebook_instance, project_tag)
         except:
             traceback.print_exc()
             raise Exception
diff --git a/infrastructure-provisioning/src/general/scripts/aws/common_start_notebook.py b/infrastructure-provisioning/src/general/scripts/aws/common_start_notebook.py
index 3bd537a..d76918b 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/common_start_notebook.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/common_start_notebook.py
@@ -33,7 +33,7 @@
 
 
 if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
diff --git a/infrastructure-provisioning/src/general/scripts/aws/common_stop_notebook.py b/infrastructure-provisioning/src/general/scripts/aws/common_stop_notebook.py
index 3d6ed46..58cc932 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/common_stop_notebook.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/common_stop_notebook.py
@@ -51,7 +51,7 @@
                 for tag in cluster.get('Tags'):
                     if tag.get('Key') == 'ComputationalName':
                         computational_name = tag.get('Value')
-                s3_cleanup(bucket_name, emr_name, os.environ['edge_user_name'])
+                s3_cleanup(bucket_name, emr_name, os.environ['project_name'])
                 print("The bucket {} has been cleaned successfully".format(bucket_name))
                 terminate_emr(cluster_id)
                 print("The EMR cluster {} has been terminated successfully".format(emr_name))
@@ -87,7 +87,7 @@
 
 
 if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
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 c1e6bf7..4a6edac7 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/common_terminate_notebook.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/common_terminate_notebook.py
@@ -42,7 +42,7 @@
                 cluster = cluster.get("Cluster")
                 emr_name = cluster.get('Name')
                 print('Cleaning bucket from configs for cluster {}'.format(emr_name))
-                s3_cleanup(bucket_name, emr_name, os.environ['edge_user_name'])
+                s3_cleanup(bucket_name, emr_name, os.environ['project_name'])
                 print("The bucket {} has been cleaned successfully".format(bucket_name))
                 print('Terminating cluster {}'.format(emr_name))
                 terminate_emr(cluster_id)
@@ -66,7 +66,7 @@
 
 
 if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
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 7652900..5e7e52f 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_configure.py
@@ -157,7 +157,7 @@
 
 
 if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -192,30 +192,30 @@
     emr_conf['network_type'] = os.environ['conf_network_type']
     emr_conf['role_service_name'] = os.environ['emr_service_role']
     emr_conf['role_ec2_name'] = os.environ['emr_ec2_role']
-    emr_conf['tags'] = 'Name=' + emr_conf['service_base_name'] + '-' + os.environ['edge_user_name'] + '-des-' + \
+    emr_conf['tags'] = 'Name=' + emr_conf['service_base_name'] + '-' + os.environ['project_name'] + '-des-' + \
                        emr_conf['exploratory_name'] + '-' + emr_conf['computational_name'] + '-' + args.uuid + \
                        ', ' + emr_conf['service_base_name'] + '-Tag=' + emr_conf['service_base_name'] + '-' + \
-                       os.environ['edge_user_name'] + '-des-' + emr_conf['exploratory_name'] + '-' + \
+                       os.environ['project_name'] + '-des-' + emr_conf['exploratory_name'] + '-' + \
                        emr_conf['computational_name'] + '-' + args.uuid + \
                        ', Notebook=' + os.environ['notebook_instance_name'] + ', State=not-configured'
-    emr_conf['cluster_name'] = emr_conf['service_base_name'] + '-' + os.environ['edge_user_name'] + '-des-' + \
+    emr_conf['cluster_name'] = emr_conf['service_base_name'] + '-' + os.environ['project_name'] + '-des-' + \
                                emr_conf['exploratory_name'] + '-' + emr_conf['computational_name'] + '-' + \
                                args.uuid
     emr_conf['bucket_name'] = (emr_conf['service_base_name'] + '-ssn-bucket').lower().replace('_', '-')
 
     tag = {"Key": "{}-Tag".format(emr_conf['service_base_name']), "Value": "{}-{}-subnet".format(
-        emr_conf['service_base_name'], os.environ['edge_user_name'])}
+        emr_conf['service_base_name'], os.environ['project_name'])}
     emr_conf['subnet_cidr'] = get_subnet_by_tag(tag)
     emr_conf['key_path'] = os.environ['conf_key_dir'] + '/' + os.environ['conf_key_name'] + '.pem'
     emr_conf['all_ip_cidr'] = '0.0.0.0/0'
     emr_conf['additional_emr_sg_name'] = '{}-{}-de-se-additional-sg'.format(emr_conf['service_base_name'],
-                                                                          os.environ['edge_user_name'])
+                                                                          os.environ['project_name'])
     emr_conf['vpc_id'] = os.environ['aws_vpc_id']
     emr_conf['cluster_id'] = get_emr_id_by_name(emr_conf['cluster_name'])
     emr_conf['cluster_instances'] = get_emr_instances_list(emr_conf['cluster_id'])
     emr_conf['cluster_master_instances'] = get_emr_instances_list(emr_conf['cluster_id'], 'MASTER')
     emr_conf['cluster_core_instances'] = get_emr_instances_list(emr_conf['cluster_id'], 'CORE')
-    emr_conf['edge_instance_name'] = emr_conf['service_base_name'] + "-" + os.environ['edge_user_name'] + '-edge'
+    emr_conf['edge_instance_name'] = emr_conf['service_base_name'] + "-" + os.environ['project_name'] + '-edge'
     emr_conf['edge_instance_hostname'] = get_instance_private_ip_address(emr_conf['tag_name'],
                                                                          emr_conf['edge_instance_name'])
     if emr_conf['network_type'] == 'private':
@@ -224,7 +224,7 @@
     else:
         emr_conf['edge_instance_ip'] = get_instance_ip_address(emr_conf['tag_name'],
                                                                emr_conf['edge_instance_name']).get('Public')
-    emr_conf['user_keyname'] = os.environ['edge_user_name']
+    emr_conf['user_keyname'] = os.environ['project_name']
     emr_conf['os_user'] = os.environ['conf_os_user']
     emr_conf['initial_user'] = 'ec2-user'
     emr_conf['sudo_group'] = 'wheel'
diff --git a/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_create.py b/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_create.py
index f9f9bc4..995d9a2 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_create.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_create.py
@@ -66,7 +66,7 @@
 parser.add_argument('--configurations', type=str, default='')
 parser.add_argument('--region', type=str, default='')
 parser.add_argument('--key_dir', type=str, default='')
-parser.add_argument('--edge_user_name', type=str, default='')
+parser.add_argument('--project_name', type=str, default='')
 parser.add_argument('--slave_instance_spot', type=str, default='False')
 parser.add_argument('--bid_price', type=str, default='')
 parser.add_argument('--service_base_name', type=str, default='')
@@ -100,7 +100,7 @@
            args.name,
            args.nbs_user,
            args.region,
-           args.edge_user_name,
+           args.project_name,
            args.name,
            endpoint_url)
 
@@ -123,7 +123,7 @@
            args.release_label,
            args.region,
            args.release_label,
-           args.edge_user_name,
+           args.project_name,
            args.name,
            endpoint_url)
 
@@ -172,9 +172,9 @@
     try:
         s3 = boto3.resource('s3', config=Config(signature_version='s3v4'))
         s3.meta.client.upload_file(args.key_dir + '/' +
-                                   args.edge_user_name + '.pub',
-                                   args.s3_bucket, args.edge_user_name +
-                                   '/' + args.edge_user_name + '.pub',
+                                   args.project_name + '.pub',
+                                   args.s3_bucket, args.project_name +
+                                   '/' + args.project_name + '.pub',
                                    ExtraArgs={'ServerSideEncryption': 'AES256'})
         s3.meta.client.upload_file(
             '/root/scripts/dataengine-service_key_importer.py',
@@ -194,7 +194,7 @@
                               config=Config(signature_version='s3v4'),
                               region_name=args.region)
         client.delete_object(Bucket=args.s3_bucket,
-                             Key=args.edge_user_name + '.pub')
+                             Key=args.project_name + '.pub')
 
     except Exception as err:
         logging.error("Unable to remove user key: " +
@@ -233,7 +233,7 @@
 
 def wait_emr(bucket, cluster_name, timeout, delay=30):
     deadline = time.time() + timeout
-    prefix = args.edge_user_name + '/' + cluster_name + "/config/"
+    prefix = args.project_name + '/' + cluster_name + "/config/"
     global cluster_id
     while time.time() < deadline:
         state = action_validate(cluster_id)
@@ -473,5 +473,5 @@
             out.close()
             if action_validate(cluster_id)[0] == "True":
                 terminate_emr(cluster_id)
-            s3_cleanup(args.s3_bucket, args.name, args.edge_user_name)
+            s3_cleanup(args.s3_bucket, args.name, args.project_name)
             sys.exit(1)
diff --git a/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_install_libs.py b/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_install_libs.py
index 946910b..a8a1e47 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_install_libs.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_install_libs.py
@@ -48,7 +48,7 @@
 if __name__ == "__main__":
     create_aws_config_files()
     instance_class = 'notebook'
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
diff --git a/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_list_libs.py b/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_list_libs.py
index 4c11795..e4a0f38 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_list_libs.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_list_libs.py
@@ -32,7 +32,7 @@
 
 if __name__ == "__main__":
     instance_class = 'notebook'
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
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 ef9b067..626e9dc 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_prepare.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_prepare.py
@@ -39,7 +39,7 @@
 
 
 if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -53,7 +53,7 @@
         time.sleep(30)
     create_aws_config_files()
     edge_status = get_instance_status(os.environ['conf_service_base_name'] + '-Tag',
-        os.environ['conf_service_base_name'] + '-' + os.environ['edge_user_name'] + '-edge')
+        os.environ['conf_service_base_name'] + '-' + os.environ['project_name'] + '-edge')
     if edge_status != 'running':
         logging.info('ERROR: Edge node is unavailable! Aborting...')
         print('ERROR: Edge node is unavailable! Aborting...')
@@ -81,7 +81,7 @@
     emr_conf['key_name'] = os.environ['conf_key_name']
     emr_conf['region'] = os.environ['aws_region']
     emr_conf['release_label'] = os.environ['emr_version']
-    emr_conf['edge_instance_name'] = '{0}-{1}-edge'.format(emr_conf['service_base_name'], os.environ['edge_user_name'])
+    emr_conf['edge_instance_name'] = '{0}-{1}-edge'.format(emr_conf['service_base_name'], os.environ['project_name'])
     emr_conf['edge_security_group_name'] = '{0}-SG'.format(emr_conf['edge_instance_name'])
     emr_conf['master_instance_type'] = os.environ['emr_master_instance_type']
     emr_conf['slave_instance_type'] = os.environ['emr_slave_instance_type']
@@ -96,13 +96,13 @@
                        'State=not-configured,' \
                        'ComputationalName={3}' \
         .format(emr_conf['service_base_name'],
-                os.environ['edge_user_name'],
+                os.environ['project_name'],
                 emr_conf['exploratory_name'],
                 emr_conf['computational_name'],
                 os.environ['notebook_instance_name'])
     emr_conf['cluster_name'] = '{0}-{1}-des-{2}-{3}-{4}'\
         .format(emr_conf['service_base_name'],
-                os.environ['edge_user_name'],
+                os.environ['project_name'],
                 emr_conf['exploratory_name'],
                 emr_conf['computational_name'],
                 args.uuid)
@@ -113,12 +113,12 @@
 
     tag = {"Key": "{}-Tag".format(emr_conf['service_base_name']),
            "Value": "{}-{}-subnet".format(emr_conf['service_base_name'],
-                                          os.environ['edge_user_name'])}
+                                          os.environ['project_name'])}
     emr_conf['subnet_cidr'] = 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'\
-        .format(emr_conf['service_base_name'], os.environ['edge_user_name'])
+        .format(emr_conf['service_base_name'], os.environ['project_name'])
     emr_conf['vpc_id'] = os.environ['aws_vpc_id']
     emr_conf['vpc2_id'] = os.environ['aws_notebook_vpc_id']
     if os.environ['emr_slave_instance_spot'] == 'True':
@@ -258,7 +258,7 @@
                  "--region {14} " \
                  "--tags '{15}' " \
                  "--key_dir {16} " \
-                 "--edge_user_name {17} " \
+                 "--project_name {17} " \
                  "--slave_instance_spot {18} " \
                  "--bid_price {19} " \
                  "--service_base_name {20} " \
@@ -281,7 +281,7 @@
                     emr_conf['region'],
                     emr_conf['tags'],
                     os.environ['conf_key_dir'],
-                    os.environ['edge_user_name'],
+                    os.environ['project_name'],
                     os.environ['emr_slave_instance_spot'],
                     str(emr_conf['slave_bid_price']),
                     emr_conf['service_base_name'],
diff --git a/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_terminate.py b/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_terminate.py
index a08b865..462b403 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_terminate.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/dataengine-service_terminate.py
@@ -44,7 +44,7 @@
                 for tag in cluster.get('Tags'):
                     if tag.get('Key') == 'ComputationalName':
                         computational_name = tag.get('Value')
-                s3_cleanup(bucket_name, emr_name, os.environ['edge_user_name'])
+                s3_cleanup(bucket_name, emr_name, os.environ['project_name'])
                 print("The bucket {} has been cleaned successfully".format(bucket_name))
                 terminate_emr(cluster_id)
                 print("The EMR cluster {} has been terminated successfully".format(emr_name))
@@ -58,7 +58,7 @@
 
 
 if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
diff --git a/infrastructure-provisioning/src/general/scripts/aws/dataengine_configure.py b/infrastructure-provisioning/src/general/scripts/aws/dataengine_configure.py
index 96fb8d2..c9b8bc1 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/dataengine_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/dataengine_configure.py
@@ -143,7 +143,7 @@
 
 
 if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -166,7 +166,7 @@
         data_engine['key_name'] = os.environ['conf_key_name']
         data_engine['region'] = os.environ['aws_region']
         data_engine['network_type'] = os.environ['conf_network_type']
-        data_engine['cluster_name'] = data_engine['service_base_name'] + '-' + os.environ['edge_user_name'] + \
+        data_engine['cluster_name'] = data_engine['service_base_name'] + '-' + os.environ['project_name'] + \
                                       '-de-' + data_engine['exploratory_name'] + '-' + \
                                       data_engine['computational_name']
         data_engine['master_node_name'] = data_engine['cluster_name'] + '-m'
@@ -174,21 +174,21 @@
         data_engine['master_size'] = os.environ['aws_dataengine_master_shape']
         data_engine['slave_size'] = os.environ['aws_dataengine_slave_shape']
         data_engine['dataengine_master_security_group_name'] = data_engine['service_base_name'] + '-' + \
-                                                               os.environ['edge_user_name'] + '-dataengine-master-sg'
+                                                               os.environ['project_name'] + '-dataengine-master-sg'
         data_engine['dataengine_slave_security_group_name'] = data_engine['service_base_name'] + '-' + \
-                                                              os.environ['edge_user_name'] + '-dataengine-slave-sg'
+                                                              os.environ['project_name'] + '-dataengine-slave-sg'
         data_engine['tag_name'] = data_engine['service_base_name'] + '-Tag'
         tag = {"Key": data_engine['tag_name'],
-               "Value": "{}-{}-subnet".format(data_engine['service_base_name'], os.environ['edge_user_name'])}
+               "Value": "{}-{}-subnet".format(data_engine['service_base_name'], os.environ['project_name'])}
         data_engine['subnet_cidr'] = get_subnet_by_tag(tag)
         data_engine['notebook_dataengine_role_profile_name'] = data_engine['service_base_name']. \
                                                                    lower().replace('-', '_') + "-" + \
-                                                               os.environ['edge_user_name'] + '-nb-de-Profile'
+                                                               os.environ['project_name'] + '-nb-de-Profile'
         data_engine['instance_count'] = int(os.environ['dataengine_instance_count'])
         master_node_hostname = get_instance_hostname(data_engine['tag_name'], data_engine['master_node_name'])
         data_engine['dlab_ssh_user'] = os.environ['conf_os_user']
         keyfile_name = "{}{}.pem".format(os.environ['conf_key_dir'], os.environ['conf_key_name'])
-        edge_instance_name = os.environ['conf_service_base_name'] + "-" + os.environ['edge_user_name'] + '-edge'
+        edge_instance_name = os.environ['conf_service_base_name'] + "-" + os.environ['project_name'] + '-edge'
         edge_instance_hostname = get_instance_hostname(data_engine['tag_name'], edge_instance_name)
         edge_instance_private_ip = get_instance_ip_address(data_engine['tag_name'], edge_instance_name).get('Private')
         if data_engine['network_type'] == 'private':
@@ -204,7 +204,7 @@
             sudo_group = 'wheel'
     except Exception as err:
         data_engine['tag_name'] = data_engine['service_base_name'] + '-Tag'
-        data_engine['cluster_name'] = data_engine['service_base_name'] + '-' + os.environ['edge_user_name'] + \
+        data_engine['cluster_name'] = data_engine['service_base_name'] + '-' + os.environ['project_name'] + \
                                       '-de-' + data_engine['exploratory_name'] + '-' + \
                                       data_engine['computational_name']
         data_engine['master_node_name'] = data_engine['cluster_name'] + '-m'
diff --git a/infrastructure-provisioning/src/general/scripts/aws/dataengine_prepare.py b/infrastructure-provisioning/src/general/scripts/aws/dataengine_prepare.py
index 511cad3..2a8198d 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/dataengine_prepare.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/dataengine_prepare.py
@@ -36,7 +36,7 @@
 
 
 if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -46,7 +46,7 @@
         create_aws_config_files()
         edge_status = get_instance_status(os.environ['conf_service_base_name'] + '-Tag',
                                           os.environ['conf_service_base_name'] + '-' + os.environ[
-                                              'edge_user_name'] + '-edge')
+                                              'project_name'] + '-edge')
         if edge_status != 'running':
             logging.info('ERROR: Edge node is unavailable! Aborting...')
             print('ERROR: Edge node is unavailable! Aborting...')
@@ -70,7 +70,7 @@
         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']
-        data_engine['cluster_name'] = data_engine['service_base_name'] + '-' + os.environ['edge_user_name'] + \
+        data_engine['cluster_name'] = data_engine['service_base_name'] + '-' + os.environ['project_name'] + \
                                       '-de-' + data_engine['exploratory_name'] + '-' + \
                                       data_engine['computational_name']
         data_engine['master_node_name'] = '{}-m'.format(data_engine['cluster_name'])
@@ -78,15 +78,15 @@
         data_engine['master_size'] = os.environ['aws_dataengine_master_shape']
         data_engine['slave_size'] = os.environ['aws_dataengine_slave_shape']
         data_engine['dataengine_master_security_group_name'] = '{}-{}-dataengine-master-sg' \
-            .format(data_engine['service_base_name'], os.environ['edge_user_name'])
+            .format(data_engine['service_base_name'], os.environ['project_name'])
         data_engine['dataengine_slave_security_group_name'] = '{}-{}-dataengine-slave-sg' \
-            .format(data_engine['service_base_name'], os.environ['edge_user_name'])
+            .format(data_engine['service_base_name'], os.environ['project_name'])
         data_engine['tag_name'] = '{}-Tag'.format(data_engine['service_base_name'])
         tag = {"Key": data_engine['tag_name'],
-               "Value": "{}-{}-subnet".format(data_engine['service_base_name'], os.environ['edge_user_name'])}
+               "Value": "{}-{}-subnet".format(data_engine['service_base_name'], os.environ['project_name'])}
         data_engine['subnet_cidr'] = get_subnet_by_tag(tag)
         data_engine['notebook_dataengine_role_profile_name'] = '{}-{}-nb-de-Profile' \
-            .format(data_engine['service_base_name'].lower().replace('-', '_'), os.environ['edge_user_name'])
+            .format(data_engine['service_base_name'].lower().replace('-', '_'), os.environ['project_name'])
         data_engine['instance_count'] = int(os.environ['dataengine_instance_count'])
         data_engine['cluster_nodes_tag'] = {"Key": "dataengine_notebook_name",
                                             "Value": os.environ['notebook_instance_name']}
diff --git a/infrastructure-provisioning/src/general/scripts/aws/dataengine_start.py b/infrastructure-provisioning/src/general/scripts/aws/dataengine_start.py
index 6f12119..c7b4f99 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/dataengine_start.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/dataengine_start.py
@@ -38,7 +38,7 @@
 
 if __name__ == "__main__":
     local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'],
-                                               os.environ['edge_user_name'],
+                                               os.environ['project_name'],
                                                os.environ['request_id'])
     local_log_filepath = "/logs/" + \
                          os.environ['conf_resource'] + "/" + local_log_filename
@@ -60,10 +60,10 @@
     except:
         data_engine['computational_name'] = ''
     data_engine['service_base_name'] = os.environ['conf_service_base_name']
-    data_engine['user_name'] = os.environ['edge_user_name']
+    data_engine['project_tag'] = os.environ['project_name']
     data_engine['cluster_name'] = \
         data_engine['service_base_name'] + '-' + \
-        data_engine['user_name'] + '-de-' + \
+        data_engine['project_tag'] + '-de-' + \
         data_engine['exploratory_name'] + '-' + \
         data_engine['computational_name']
 
diff --git a/infrastructure-provisioning/src/general/scripts/aws/dataengine_stop.py b/infrastructure-provisioning/src/general/scripts/aws/dataengine_stop.py
index 5349b8c..58b0691 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/dataengine_stop.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/dataengine_stop.py
@@ -38,7 +38,7 @@
 
 if __name__ == "__main__":
     local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'],
-                                               os.environ['edge_user_name'],
+                                               os.environ['project_name'],
                                                os.environ['request_id'])
     local_log_filepath = "/logs/" + \
                          os.environ['conf_resource'] + "/" + local_log_filename
@@ -59,10 +59,10 @@
     except:
         data_engine_config['computational_name'] = ''
     data_engine_config['service_base_name'] = os.environ['conf_service_base_name']
-    data_engine_config['user_name'] = os.environ['edge_user_name']
+    data_engine_config['project_tag'] = os.environ['project_name']
     data_engine_config['cluster_name'] = \
         data_engine_config['service_base_name'] + '-' \
-        + data_engine_config['user_name'] + '-de-' + \
+        + data_engine_config['project_tag'] + '-de-' + \
         data_engine_config['exploratory_name'] + '-' \
         + data_engine_config['computational_name']
 
diff --git a/infrastructure-provisioning/src/general/scripts/aws/dataengine_terminate.py b/infrastructure-provisioning/src/general/scripts/aws/dataengine_terminate.py
index daa25ae..f55ef91 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/dataengine_terminate.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/dataengine_terminate.py
@@ -48,7 +48,7 @@
 
 if __name__ == "__main__":
     local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'],
-                                               os.environ['edge_user_name'],
+                                               os.environ['project_name'],
                                                os.environ['request_id'])
     local_log_filepath = "/logs/" + \
                          os.environ['conf_resource'] + "/" + local_log_filename
@@ -70,10 +70,10 @@
         data_engine['computational_name'] = ''
     data_engine['service_base_name'] = os.environ['conf_service_base_name']
     data_engine['tag_name'] = data_engine['service_base_name'] + '-Tag'
-    data_engine['user_name'] = os.environ['edge_user_name']
+    data_engine['project_tag'] = os.environ['project_name']
     data_engine['cluster_name'] = \
         data_engine['service_base_name'] + '-' + \
-        data_engine['user_name'] + '-de-' + \
+        data_engine['project_tag'] + '-de-' + \
         data_engine['exploratory_name'] + '-' +\
         data_engine['computational_name']
     data_engine['notebook_name'] = os.environ['notebook_instance_name']
diff --git a/infrastructure-provisioning/src/general/scripts/aws/deeplearning_configure.py b/infrastructure-provisioning/src/general/scripts/aws/deeplearning_configure.py
index f98ae4d..28e2544 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/deeplearning_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/deeplearning_configure.py
@@ -36,7 +36,7 @@
 
 
 if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -51,18 +51,18 @@
     notebook_config['service_base_name'] = os.environ['conf_service_base_name']
     notebook_config['instance_type'] = os.environ['aws_notebook_instance_type']
     notebook_config['key_name'] = os.environ['conf_key_name']
-    notebook_config['user_keyname'] = os.environ['edge_user_name']
+    notebook_config['user_keyname'] = os.environ['project_name']
     notebook_config['network_type'] = os.environ['conf_network_type']
     notebook_config['instance_name'] = '{}-{}-nb-{}-{}'.format(notebook_config['service_base_name'],
-                                                               os.environ['edge_user_name'],
+                                                               os.environ['project_name'],
                                                                notebook_config['exploratory_name'], args.uuid)
     notebook_config['expected_image_name'] = '{}-{}-notebook-image'.format(notebook_config['service_base_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'].lower().replace('-', '_'), os.environ['edge_user_name'])
+        .format(notebook_config['service_base_name'].lower().replace('-', '_'), os.environ['project_name'])
     notebook_config['security_group_name'] = '{}-{}-nb-SG'.format(notebook_config['service_base_name'],
-                                                                  os.environ['edge_user_name'])
+                                                                  os.environ['project_name'])
     notebook_config['tag_name'] = '{}-Tag'.format(notebook_config['service_base_name'])
     notebook_config['dlab_ssh_user'] = os.environ['conf_os_user']
     notebook_config['shared_image_enabled'] = os.environ['conf_shared_image_enabled']
@@ -70,7 +70,7 @@
 
     # generating variables regarding EDGE proxy on Notebook instance
     instance_hostname = get_instance_hostname(notebook_config['tag_name'], notebook_config['instance_name'])
-    edge_instance_name = os.environ['conf_service_base_name'] + "-" + os.environ['edge_user_name'] + '-edge'
+    edge_instance_name = os.environ['conf_service_base_name'] + "-" + os.environ['project_name'] + '-edge'
     edge_instance_hostname = get_instance_hostname(notebook_config['tag_name'], edge_instance_name)
     edge_instance_private_ip = get_instance_ip_address(notebook_config['tag_name'], edge_instance_name).get('Private')
     if notebook_config['network_type'] == 'private':
diff --git a/infrastructure-provisioning/src/general/scripts/aws/edge_associate_elastic_ip.py b/infrastructure-provisioning/src/general/scripts/aws/edge_associate_elastic_ip.py
index bfc2df9..131ac46 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/edge_associate_elastic_ip.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/edge_associate_elastic_ip.py
@@ -36,7 +36,7 @@
 args = parser.parse_args()
 
 if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
diff --git a/infrastructure-provisioning/src/general/scripts/aws/edge_configure.py b/infrastructure-provisioning/src/general/scripts/aws/edge_configure.py
index cf69adb..c215fd2 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/edge_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/edge_configure.py
@@ -28,7 +28,7 @@
 from dlab.actions_lib import *
 
 if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'],
                                                os.environ['request_id'])
     local_log_filepath = "/logs/edge/" + local_log_filename
     logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
@@ -39,23 +39,23 @@
     edge_conf = dict()
     edge_conf['service_base_name'] = os.environ['conf_service_base_name']
     edge_conf['key_name'] = os.environ['conf_key_name']
-    edge_conf['user_keyname'] = os.environ['edge_user_name']
-    edge_conf['instance_name'] = '{}-{}-edge'.format(edge_conf['service_base_name'], os.environ['edge_user_name'])
+    edge_conf['user_key'] = os.environ['key']
+    edge_conf['instance_name'] = '{}-{}-edge'.format(edge_conf['service_base_name'], os.environ['project_name'])
     edge_conf['tag_name'] = edge_conf['service_base_name'] + '-Tag'
     edge_conf['bucket_name'] = '{}-{}-bucket'.format(edge_conf['service_base_name'],
-                                                     os.environ['edge_user_name']).lower().replace('_', '-')
+                                                     os.environ['project_name']).lower().replace('_', '-')
     edge_conf['shared_bucket_name'] = (edge_conf['service_base_name'] + '-shared-bucket').lower().replace('_', '-')
     edge_conf['edge_security_group_name'] = '{}-SG'.format(edge_conf['instance_name'])
     edge_conf['notebook_instance_name'] = '{}-{}-nb'.format(edge_conf['service_base_name'],
-                                                            os.environ['edge_user_name'])
+                                                            os.environ['project_name'])
     edge_conf['notebook_role_profile_name'] = '{}-{}-nb-Profile' \
-        .format(edge_conf['service_base_name'].lower().replace('-', '_'), os.environ['edge_user_name'])
+        .format(edge_conf['service_base_name'].lower().replace('-', '_'), os.environ['project_name'])
     edge_conf['notebook_security_group_name'] = '{}-{}-nb-SG'.format(edge_conf['service_base_name'],
-                                                                     os.environ['edge_user_name'])
+                                                                     os.environ['project_name'])
     edge_conf['dataengine_instances_name'] = '{}-{}-dataengine' \
-        .format(edge_conf['service_base_name'], os.environ['edge_user_name'])
+        .format(edge_conf['service_base_name'], os.environ['project_name'])
     tag = {"Key": edge_conf['tag_name'],
-           "Value": "{}-{}-subnet".format(edge_conf['service_base_name'], os.environ['edge_user_name'])}
+           "Value": "{}-{}-subnet".format(edge_conf['service_base_name'], os.environ['project_name'])}
     edge_conf['private_subnet_cidr'] = get_subnet_by_tag(tag)
     edge_conf['dlab_ssh_user'] = os.environ['conf_os_user']
     edge_conf['network_type'] = os.environ['conf_network_type']
@@ -69,8 +69,12 @@
             'Private')
         edge_conf['edge_public_ip'] = edge_conf['edge_private_ip']
     edge_conf['vpc1_cidrs'] = get_vpc_cidr_by_id(os.environ['aws_vpc_id'])
-    edge_conf['vpc2_cidrs'] = get_vpc_cidr_by_id(os.environ['aws_notebook_vpc_id'])
-    edge_conf['vpc_cidrs'] = list(set(edge_conf['vpc1_cidrs'] + edge_conf['vpc2_cidrs']))
+    try:
+        edge_conf['vpc2_cidrs'] = get_vpc_cidr_by_id(os.environ['aws_notebook_vpc_id'])
+        edge_conf['vpc_cidrs'] = list(set(edge_conf['vpc1_cidrs'] + edge_conf['vpc2_cidrs']))
+    except KeyError:
+        edge_conf['vpc_cidrs'] = list(set(edge_conf['vpc1_cidrs']))
+
     edge_conf['allowed_ip_cidr'] = list()
     for cidr in os.environ['conf_allowed_ip_cidr'].split(','):
         edge_conf['allowed_ip_cidr'].append(cidr.replace(' ', ''))
@@ -101,13 +105,13 @@
     except Exception as err:
         print('Error: {0}'.format(err))
         append_result("Failed creating ssh user 'dlab'.", str(err))
-        remove_all_iam_resources('notebook', os.environ['edge_user_name'])
-        remove_all_iam_resources('edge', os.environ['edge_user_name'])
+        remove_all_iam_resources('notebook', os.environ['project_name'])
+        remove_all_iam_resources('edge', os.environ['project_name'])
         remove_ec2(edge_conf['tag_name'], edge_conf['instance_name'])
         remove_sgroups(edge_conf['dataengine_instances_name'])
         remove_sgroups(edge_conf['notebook_instance_name'])
         remove_sgroups(edge_conf['instance_name'])
-        remove_s3('edge', os.environ['edge_user_name'])
+        remove_s3('edge', os.environ['project_name'])
         sys.exit(1)
 
     try:
@@ -123,13 +127,13 @@
     except Exception as err:
         print('Error: {0}'.format(err))
         append_result("Failed installing apps: apt & pip.", str(err))
-        remove_all_iam_resources('notebook', os.environ['edge_user_name'])
-        remove_all_iam_resources('edge', os.environ['edge_user_name'])
+        remove_all_iam_resources('notebook', os.environ['project_name'])
+        remove_all_iam_resources('edge', os.environ['project_name'])
         remove_ec2(edge_conf['tag_name'], edge_conf['instance_name'])
         remove_sgroups(edge_conf['dataengine_instances_name'])
         remove_sgroups(edge_conf['notebook_instance_name'])
         remove_sgroups(edge_conf['instance_name'])
-        remove_s3('edge', os.environ['edge_user_name'])
+        remove_s3('edge', os.environ['project_name'])
         sys.exit(1)
 
     try:
@@ -137,7 +141,7 @@
         logging.info('[INSTALLING HTTP PROXY]')
         additional_config = {"exploratory_subnet": edge_conf['private_subnet_cidr'],
                              "template_file": "/root/templates/squid.conf",
-                             "edge_user_name": os.environ['aws_iam_user'],
+                             "project_name": os.environ['project_name'],
                              "ldap_host": os.environ['ldap_hostname'],
                              "ldap_dn": os.environ['ldap_dn'],
                              "ldap_user": os.environ['ldap_service_username'],
@@ -154,21 +158,22 @@
     except Exception as err:
         print('Error: {0}'.format(err))
         append_result("Failed installing http proxy.", str(err))
-        remove_all_iam_resources('notebook', os.environ['edge_user_name'])
-        remove_all_iam_resources('edge', os.environ['edge_user_name'])
+        remove_all_iam_resources('notebook', os.environ['project_name'])
+        remove_all_iam_resources('edge', os.environ['project_name'])
         remove_ec2(edge_conf['tag_name'], edge_conf['instance_name'])
         remove_sgroups(edge_conf['dataengine_instances_name'])
         remove_sgroups(edge_conf['notebook_instance_name'])
         remove_sgroups(edge_conf['instance_name'])
-        remove_s3('edge', os.environ['edge_user_name'])
+        remove_s3('edge', os.environ['project_name'])
         sys.exit(1)
 
 
     try:
         print('[INSTALLING USERs KEY]')
         logging.info('[INSTALLING USERs KEY]')
-        additional_config = {"user_keyname": edge_conf['user_keyname'],
-                             "user_keydir": os.environ['conf_key_dir']}
+        additional_config = {"user_keyname": os.environ['project_name'],
+                             "user_keydir": os.environ['conf_key_dir'],
+                             "user_key": edge_conf['user_key']}
         params = "--hostname {} --keyfile {} --additional_config '{}' --user {}".format(
             instance_hostname, keyfile_name, json.dumps(additional_config), edge_conf['dlab_ssh_user'])
         try:
@@ -179,13 +184,13 @@
     except Exception as err:
         print('Error: {0}'.format(err))
         append_result("Failed installing users key." + str(err))
-        remove_all_iam_resources('notebook', os.environ['edge_user_name'])
-        remove_all_iam_resources('edge', os.environ['edge_user_name'])
+        remove_all_iam_resources('notebook', os.environ['project_name'])
+        remove_all_iam_resources('edge', os.environ['project_name'])
         remove_ec2(edge_conf['tag_name'], edge_conf['instance_name'])
         remove_sgroups(edge_conf['dataengine_instances_name'])
         remove_sgroups(edge_conf['notebook_instance_name'])
         remove_sgroups(edge_conf['instance_name'])
-        remove_s3('edge', os.environ['edge_user_name'])
+        remove_s3('edge', os.environ['project_name'])
         sys.exit(1)
 
     try:
@@ -201,13 +206,13 @@
     except Exception as err:
         print('Error: {0}'.format(err))
         append_result("Failed installing nginx reverse proxy." + str(err))
-        remove_all_iam_resources('notebook', os.environ['edge_user_name'])
-        remove_all_iam_resources('edge', os.environ['edge_user_name'])
+        remove_all_iam_resources('notebook', os.environ['project_name'])
+        remove_all_iam_resources('edge', os.environ['project_name'])
         remove_ec2(edge_conf['tag_name'], edge_conf['instance_name'])
         remove_sgroups(edge_conf['dataengine_instances_name'])
         remove_sgroups(edge_conf['notebook_instance_name'])
         remove_sgroups(edge_conf['instance_name'])
-        remove_s3('edge', os.environ['edge_user_name'])
+        remove_s3('edge', os.environ['project_name'])
         sys.exit(1)
 
     try:
@@ -240,6 +245,7 @@
                    "edge_sg": edge_conf['edge_security_group_name'],
                    "notebook_subnet": edge_conf['private_subnet_cidr'],
                    "full_edge_conf": edge_conf,
+                   "project_name": os.environ['project_name'],
                    "Action": "Create new EDGE server"}
             print(json.dumps(res))
             result.write(json.dumps(res))
diff --git a/infrastructure-provisioning/src/general/scripts/aws/edge_prepare.py b/infrastructure-provisioning/src/general/scripts/aws/edge_prepare.py
deleted file mode 100644
index ef7660a..0000000
--- a/infrastructure-provisioning/src/general/scripts/aws/edge_prepare.py
+++ /dev/null
@@ -1,573 +0,0 @@
-#!/usr/bin/python
-
-# *****************************************************************************
-#
-# 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 json
-from dlab.fab import *
-from dlab.meta_lib import *
-import sys, time, os
-from dlab.actions_lib import *
-import traceback
-
-
-if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
-                                               os.environ['request_id'])
-    local_log_filepath = "/logs/edge/" + local_log_filename
-    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
-                        level=logging.DEBUG,
-                        filename=local_log_filepath)
-
-    create_aws_config_files()
-    print('Generating infrastructure names and tags')
-    edge_conf = dict()
-    edge_conf['service_base_name'] = os.environ['conf_service_base_name']
-    edge_conf['key_name'] = os.environ['conf_key_name']
-    edge_conf['user_keyname'] = os.environ['edge_user_name']
-    edge_conf['public_subnet_id'] = os.environ['aws_subnet_id']
-    edge_conf['vpc_id'] = os.environ['aws_vpc_id']
-    edge_conf['vpc2_id'] = os.environ['aws_notebook_vpc_id']
-    edge_conf['region'] = os.environ['aws_region']
-    edge_conf['ami_id'] = get_ami_id(os.environ['aws_{}_image_name'.format(os.environ['conf_os_family'])])
-    edge_conf['instance_size'] = os.environ['aws_edge_instance_size']
-    edge_conf['sg_ids'] = os.environ['aws_security_groups_ids']
-    edge_conf['instance_name'] = '{}-{}-edge'.format(edge_conf['service_base_name'], os.environ['edge_user_name'])
-    edge_conf['tag_name'] = '{}-Tag'.format(edge_conf['service_base_name'])
-    edge_conf['bucket_name_tag'] = '{}-{}-bucket'.format(edge_conf['service_base_name'],
-                                                     os.environ['edge_user_name'])
-    edge_conf['bucket_name'] = edge_conf['bucket_name_tag'].lower().replace('_', '-')
-    edge_conf['ssn_bucket_name'] = '{}-ssn-bucket'.format(edge_conf['service_base_name']).lower().replace('_', '-')
-    edge_conf['shared_bucket_name'] = '{}-shared-bucket'.format(edge_conf['service_base_name']).lower().replace('_',
-                                                                                                                '-')
-    edge_conf['role_name'] = '{}-{}-edge-Role'.format(edge_conf['service_base_name'].lower().replace('-', '_'),
-                                                      os.environ['edge_user_name'])
-    edge_conf['role_profile_name'] = '{}-{}-edge-Profile'.format(edge_conf['service_base_name'].lower().replace('-',
-                                                                                                                '_'),
-                                                                 os.environ['edge_user_name'])
-    edge_conf['policy_name'] = '{}-{}-edge-Policy'.format(edge_conf['service_base_name'].lower().replace('-', '_'),
-                                                          os.environ['edge_user_name'])
-    edge_conf['edge_security_group_name'] = '{}-SG'.format(edge_conf['instance_name'])
-    edge_conf['notebook_instance_name'] = '{}-{}-nb'.format(edge_conf['service_base_name'],
-                                                            os.environ['edge_user_name'])
-    edge_conf['dataengine_instances_name'] = '{}-{}-dataengine' \
-        .format(edge_conf['service_base_name'], os.environ['edge_user_name'])
-    edge_conf['notebook_dataengine_role_name'] = '{}-{}-nb-de-Role' \
-        .format(edge_conf['service_base_name'].lower().replace('-', '_'), os.environ['edge_user_name'])
-    edge_conf['notebook_dataengine_policy_name'] = '{}-{}-nb-de-Policy' \
-        .format(edge_conf['service_base_name'].lower().replace('-', '_'), os.environ['edge_user_name'])
-    edge_conf['notebook_dataengine_role_profile_name'] = '{}-{}-nb-de-Profile' \
-        .format(edge_conf['service_base_name'].lower().replace('-', '_'), os.environ['edge_user_name'])
-    edge_conf['notebook_security_group_name'] = '{}-{}-nb-SG'.format(edge_conf['service_base_name'],
-                                                                     os.environ['edge_user_name'])
-    edge_conf['private_subnet_prefix'] = os.environ['aws_private_subnet_prefix']
-    edge_conf['private_subnet_name'] = '{0}-{1}-subnet'.format(edge_conf['service_base_name'],
-                                                               os.environ['edge_user_name'])
-    edge_conf['dataengine_master_security_group_name'] = '{}-{}-dataengine-master-sg' \
-        .format(edge_conf['service_base_name'], os.environ['edge_user_name'])
-    edge_conf['dataengine_slave_security_group_name'] = '{}-{}-dataengine-slave-sg' \
-        .format(edge_conf['service_base_name'], os.environ['edge_user_name'])
-    edge_conf['allowed_ip_cidr'] = list()
-    for cidr in os.environ['conf_allowed_ip_cidr'].split(','):
-        edge_conf['allowed_ip_cidr'].append({"CidrIp": cidr.replace(' ','')})
-    edge_conf['network_type'] = os.environ['conf_network_type']
-    edge_conf['all_ip_cidr'] = '0.0.0.0/0'
-    edge_conf['zone'] = os.environ['aws_region'] + os.environ['aws_zone']
-    edge_conf['elastic_ip_name'] = '{0}-{1}-edge-EIP'.format(edge_conf['service_base_name'],
-                                                             os.environ['edge_user_name'])
-    if 'aws_user_predefined_s3_policies' not in os.environ:
-        os.environ['aws_user_predefined_s3_policies'] = 'None'
-
-    try:
-        if os.environ['conf_user_subnets_range'] == '':
-            raise KeyError
-    except KeyError:
-        os.environ['conf_user_subnets_range'] = ''
-
-    # FUSE in case of absence of user's key
-    fname = "{}{}.pub".format(os.environ['conf_key_dir'], edge_conf['user_keyname'])
-    if not os.path.isfile(fname):
-        print("USERs PUBLIC KEY DOES NOT EXIST in {}".format(fname))
-        sys.exit(1)
-
-    print("Will create exploratory environment with edge node as access point as following: {}".
-          format(json.dumps(edge_conf, sort_keys=True, indent=4, separators=(',', ': '))))
-    logging.info(json.dumps(edge_conf))
-
-    try:
-        logging.info('[CREATE SUBNET]')
-        print('[CREATE SUBNET]')
-        params = "--vpc_id '{}' --infra_tag_name {} --infra_tag_value {} --username {} --prefix {} " \
-                 "--user_subnets_range '{}' --subnet_name {} --zone {}".format(
-            edge_conf['vpc2_id'], edge_conf['tag_name'], edge_conf['service_base_name'], os.environ['edge_user_name'],
-            edge_conf['private_subnet_prefix'], os.environ['conf_user_subnets_range'], edge_conf['private_subnet_name'],
-            edge_conf['zone'])
-        try:
-            local("~/scripts/{}.py {}".format('common_create_subnet', params))
-        except:
-            traceback.print_exc()
-            raise Exception
-    except Exception as err:
-        print('Error: {0}'.format(err))
-        append_result("Failed to create subnet.", str(err))
-        sys.exit(1)
-
-    tag = {"Key": edge_conf['tag_name'], "Value": "{}-{}-subnet".format(edge_conf['service_base_name'],
-                                                                        os.environ['edge_user_name'])}
-    edge_conf['private_subnet_cidr'] = get_subnet_by_tag(tag)
-    print('NEW SUBNET CIDR CREATED: {}'.format(edge_conf['private_subnet_cidr']))
-
-    try:
-        logging.info('[CREATE EDGE ROLES]')
-        print('[CREATE EDGE ROLES]')
-        params = "--role_name {} --role_profile_name {} --policy_name {} --region {} --infra_tag_name {} " \
-                 "--infra_tag_value {}" \
-                 .format(edge_conf['role_name'], edge_conf['role_profile_name'],
-                         edge_conf['policy_name'], os.environ['aws_region'], edge_conf['tag_name'],
-                         edge_conf['service_base_name'])
-        try:
-            local("~/scripts/{}.py {}".format('common_create_role_policy', params))
-        except:
-            traceback.print_exc()
-            raise Exception
-    except Exception as err:
-        print('Error: {0}'.format(err))
-        append_result("Failed to creating roles.", str(err))
-        sys.exit(1)
-
-    try:
-        logging.info('[CREATE BACKEND (NOTEBOOK) ROLES]')
-        print('[CREATE BACKEND (NOTEBOOK) ROLES]')
-        params = "--role_name {} --role_profile_name {} --policy_name {} --region {} --infra_tag_name {} " \
-                 "--infra_tag_value {}" \
-                 .format(edge_conf['notebook_dataengine_role_name'], edge_conf['notebook_dataengine_role_profile_name'],
-                         edge_conf['notebook_dataengine_policy_name'], os.environ['aws_region'], edge_conf['tag_name'],
-                         edge_conf['service_base_name'])
-        try:
-            local("~/scripts/{}.py {}".format('common_create_role_policy', params))
-        except:
-            traceback.print_exc()
-            raise Exception
-    except Exception as err:
-        print('Error: {0}'.format(err))
-        append_result("Failed to creating roles.", str(err))
-        remove_all_iam_resources('edge', os.environ['edge_user_name'])
-        sys.exit(1)
-
-    try:
-        logging.info('[CREATE SECURITY GROUP FOR EDGE NODE]')
-        print('[CREATE SECURITY GROUPS FOR EDGE]')
-        edge_sg_ingress = format_sg([
-            {
-                "IpProtocol": "-1",
-                "IpRanges": [{"CidrIp": edge_conf['private_subnet_cidr']}],
-                "UserIdGroupPairs": [], "PrefixListIds": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 22,
-                "IpRanges": edge_conf['allowed_ip_cidr'],
-                "ToPort": 22, "IpProtocol": "tcp", "UserIdGroupPairs": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 3128,
-                "IpRanges": edge_conf['allowed_ip_cidr'],
-                "ToPort": 3128, "IpProtocol": "tcp", "UserIdGroupPairs": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 80,
-                "IpRanges": edge_conf['allowed_ip_cidr'],
-                "ToPort": 80, "IpProtocol": "tcp", "UserIdGroupPairs": []
-            },
-            {
-                "IpProtocol": "-1",
-                "IpRanges": [{"CidrIp": get_instance_ip_address(edge_conf['tag_name'], '{}-ssn'.format(
-                    edge_conf['service_base_name'])).get('Private') + "/32"}],
-                "UserIdGroupPairs": [],
-                "PrefixListIds": []
-            }
-        ])
-        edge_sg_egress = format_sg([
-            {
-                "PrefixListIds": [],
-                "FromPort": 22,
-                "IpRanges": [{"CidrIp": edge_conf['private_subnet_cidr']}],
-                "ToPort": 22, "IpProtocol": "tcp", "UserIdGroupPairs": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 8888,
-                "IpRanges": [{"CidrIp": edge_conf['private_subnet_cidr']}],
-                "ToPort": 8888, "IpProtocol": "tcp", "UserIdGroupPairs": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 8080,
-                "IpRanges": [{"CidrIp": edge_conf['private_subnet_cidr']}],
-                "ToPort": 8080, "IpProtocol": "tcp", "UserIdGroupPairs": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 8787,
-                "IpRanges": [{"CidrIp": edge_conf['private_subnet_cidr']}],
-                "ToPort": 8787, "IpProtocol": "tcp", "UserIdGroupPairs": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 6006,
-                "IpRanges": [{"CidrIp": edge_conf['private_subnet_cidr']}],
-                "ToPort": 6006, "IpProtocol": "tcp", "UserIdGroupPairs": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 20888,
-                "IpRanges": [{"CidrIp": edge_conf['private_subnet_cidr']}],
-                "ToPort": 20888, "IpProtocol": "tcp", "UserIdGroupPairs": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 8042,
-                "IpRanges": [{"CidrIp": edge_conf['private_subnet_cidr']}],
-                "ToPort": 8042, "IpProtocol": "tcp", "UserIdGroupPairs": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 8088,
-                "IpRanges": [{"CidrIp": edge_conf['private_subnet_cidr']}],
-                "ToPort": 8088, "IpProtocol": "tcp", "UserIdGroupPairs": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 8081,
-                "IpRanges": [{"CidrIp": edge_conf['private_subnet_cidr']}],
-                "ToPort": 8081, "IpProtocol": "tcp", "UserIdGroupPairs": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 4040,
-                "IpRanges": [{"CidrIp": edge_conf['private_subnet_cidr']}],
-                "ToPort": 4140, "IpProtocol": "tcp", "UserIdGroupPairs": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 18080,
-                "IpRanges": [{"CidrIp": edge_conf['private_subnet_cidr']}],
-                "ToPort": 18080, "IpProtocol": "tcp", "UserIdGroupPairs": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 50070,
-                "IpRanges": [{"CidrIp": edge_conf['private_subnet_cidr']}],
-                "ToPort": 50070, "IpProtocol": "tcp", "UserIdGroupPairs": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 53,
-                "IpRanges": [{"CidrIp": edge_conf['all_ip_cidr']}],
-                "ToPort": 53, "IpProtocol": "udp", "UserIdGroupPairs": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 80,
-                "IpRanges": [{"CidrIp": edge_conf['all_ip_cidr']}],
-                "ToPort": 80, "IpProtocol": "tcp", "UserIdGroupPairs": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 123,
-                "IpRanges": [{"CidrIp": edge_conf['all_ip_cidr']}],
-                "ToPort": 123, "IpProtocol": "udp", "UserIdGroupPairs": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 443,
-                "IpRanges": [{"CidrIp": edge_conf['all_ip_cidr']}],
-                "ToPort": 443, "IpProtocol": "tcp", "UserIdGroupPairs": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 8085,
-                "IpRanges": [{"CidrIp": edge_conf['private_subnet_cidr']}],
-                "ToPort": 8085, "IpProtocol": "tcp", "UserIdGroupPairs": []
-            },
-            {
-                "PrefixListIds": [],
-                "FromPort": 389,
-                "IpRanges": [{"CidrIp": edge_conf['all_ip_cidr']}],
-                "ToPort": 389, "IpProtocol": "tcp", "UserIdGroupPairs": []
-            }
-        ])
-        params = "--name {} --vpc_id {} --security_group_rules '{}' --infra_tag_name {} --infra_tag_value {} \
-            --egress '{}' --force {} --nb_sg_name {} --resource {}".\
-            format(edge_conf['edge_security_group_name'], edge_conf['vpc_id'], json.dumps(edge_sg_ingress),
-                   edge_conf['service_base_name'], edge_conf['instance_name'], json.dumps(edge_sg_egress),
-                   True, edge_conf['notebook_instance_name'], 'edge')
-        try:
-            local("~/scripts/{}.py {}".format('common_create_security_group', params))
-        except Exception as err:
-            traceback.print_exc()
-            append_result("Failed creating security group for edge node.", str(err))
-            raise Exception
-
-        with hide('stderr', 'running', 'warnings'):
-            print('Waiting for changes to propagate')
-            time.sleep(10)
-    except:
-        remove_all_iam_resources('notebook', os.environ['edge_user_name'])
-        remove_all_iam_resources('edge', os.environ['edge_user_name'])
-        sys.exit(1)
-
-    try:
-        logging.info('[CREATE SECURITY GROUP FOR PRIVATE SUBNET]')
-        print('[CREATE SECURITY GROUP FOR PRIVATE SUBNET]')
-        edge_group_id = check_security_group(edge_conf['edge_security_group_name'])
-        sg_list = edge_conf['sg_ids'].replace(" ", "").split(',')
-        rules_list = []
-        for i in sg_list:
-            rules_list.append({"GroupId": i})
-        private_sg_ingress = format_sg([
-            {
-                "IpProtocol": "-1",
-                "IpRanges": [],
-                "UserIdGroupPairs": [{"GroupId": edge_group_id}],
-                "PrefixListIds": []
-            },
-            {
-                "IpProtocol": "-1",
-                "IpRanges": [{"CidrIp": edge_conf['private_subnet_cidr']}],
-                "UserIdGroupPairs": [],
-                "PrefixListIds": []
-            },
-            {
-                "IpProtocol": "-1",
-                "IpRanges": [{"CidrIp": get_instance_ip_address(edge_conf['tag_name'], '{}-ssn'.format(
-                    edge_conf['service_base_name'])).get('Private') + "/32"}],
-                "UserIdGroupPairs": [],
-                "PrefixListIds": []
-            }
-        ])
-
-        private_sg_egress = format_sg([
-            {
-                "IpProtocol": "-1",
-                "IpRanges": [{"CidrIp": edge_conf['private_subnet_cidr']}],
-                "UserIdGroupPairs": [],
-                "PrefixListIds": []
-            },
-            {
-                "IpProtocol": "-1",
-                "IpRanges": [{"CidrIp": get_instance_ip_address(edge_conf['tag_name'], '{}-ssn'.format(
-                    edge_conf['service_base_name'])).get('Private') + "/32"}],
-                "UserIdGroupPairs": [],
-                "PrefixListIds": [],
-            },
-            {
-                "IpProtocol": "-1",
-                "IpRanges": [],
-                "UserIdGroupPairs": [{"GroupId": edge_group_id}],
-                "PrefixListIds": []
-            },
-            {
-                "IpProtocol": "tcp",
-                "IpRanges": [{"CidrIp": edge_conf['all_ip_cidr']}],
-                "FromPort": 443,
-                "ToPort": 443,
-                "UserIdGroupPairs": [],
-                "PrefixListIds": [],
-            }
-        ])
-
-        params = "--name {} --vpc_id {} --security_group_rules '{}' --egress '{}' --infra_tag_name {} " \
-                 "--infra_tag_value {} --force {}".format(edge_conf['notebook_security_group_name'],
-                                                          edge_conf['vpc2_id'], json.dumps(private_sg_ingress),
-                                                          json.dumps(private_sg_egress), edge_conf['service_base_name'],
-                                                          edge_conf['notebook_instance_name'], True)
-        try:
-            local("~/scripts/{}.py {}".format('common_create_security_group', params))
-        except:
-            traceback.print_exc()
-            raise Exception
-
-        with hide('stderr', 'running', 'warnings'):
-            print('Waiting for changes to propagate')
-            time.sleep(10)
-    except Exception as err:
-        print('Error: {0}'.format(err))
-        append_result("Failed creating security group for private subnet.", str(err))
-        remove_all_iam_resources('notebook', os.environ['edge_user_name'])
-        remove_all_iam_resources('edge', os.environ['edge_user_name'])
-        remove_sgroups(edge_conf['notebook_instance_name'])
-        remove_sgroups(edge_conf['instance_name'])
-        sys.exit(1)
-
-    logging.info('[CREATING SECURITY GROUPS FOR MASTER NODE]')
-    print("[CREATING SECURITY GROUPS FOR MASTER NODE]")
-    try:
-        params = "--name {} --vpc_id {} --security_group_rules '{}' --egress '{}' --infra_tag_name {} " \
-                 "--infra_tag_value {} --force {}".format(edge_conf['dataengine_master_security_group_name'],
-                                                          edge_conf['vpc2_id'], json.dumps(private_sg_ingress),
-                                                          json.dumps(private_sg_egress), edge_conf['service_base_name'],
-                                                          edge_conf['dataengine_instances_name'], True)
-        try:
-            local("~/scripts/{}.py {}".format('common_create_security_group', params))
-        except:
-            traceback.print_exc()
-            raise Exception
-    except Exception as err:
-        print('Error: {0}'.format(err))
-        append_result("Failed to create sg.", str(err))
-        remove_all_iam_resources('notebook', os.environ['edge_user_name'])
-        remove_all_iam_resources('edge', os.environ['edge_user_name'])
-        remove_sgroups(edge_conf['notebook_instance_name'])
-        remove_sgroups(edge_conf['instance_name'])
-        sys.exit(1)
-
-    logging.info('[CREATING SECURITY GROUPS FOR SLAVE NODES]')
-    print("[CREATING SECURITY GROUPS FOR SLAVE NODES]")
-    try:
-        params = "--name {} --vpc_id {} --security_group_rules '{}' --egress '{}' --infra_tag_name {} " \
-                 "--infra_tag_value {} --force {}".format(edge_conf['dataengine_slave_security_group_name'],
-                                                          edge_conf['vpc2_id'], json.dumps(private_sg_ingress),
-                                                          json.dumps(private_sg_egress), edge_conf['service_base_name'],
-                                                          edge_conf['dataengine_instances_name'], True)
-        try:
-            local("~/scripts/{}.py {}".format('common_create_security_group', params))
-        except:
-            traceback.print_exc()
-            raise Exception
-    except Exception as err:
-        print('Error: {0}'.format(err))
-        append_result("Failed to create bucket.", str(err))
-        remove_all_iam_resources('notebook', os.environ['edge_user_name'])
-        remove_all_iam_resources('edge', os.environ['edge_user_name'])
-        remove_sgroups(edge_conf['dataengine_instances_name'])
-        remove_sgroups(edge_conf['notebook_instance_name'])
-        remove_sgroups(edge_conf['instance_name'])
-        sys.exit(1)
-
-    try:
-        logging.info('[CREATE BUCKETS]')
-        print('[CREATE BUCKETS]')
-        params = "--bucket_name {} --infra_tag_name {} --infra_tag_value {} --region {} --bucket_name_tag {}" \
-                 .format(edge_conf['bucket_name'], edge_conf['tag_name'], edge_conf['bucket_name'],
-                         edge_conf['region'], edge_conf['bucket_name_tag'])
-        try:
-            local("~/scripts/{}.py {}".format('common_create_bucket', params))
-        except:
-            traceback.print_exc()
-            raise Exception
-    except Exception as err:
-        print('Error: {0}'.format(err))
-        append_result("Failed to create bucket.", str(err))
-        remove_all_iam_resources('notebook', os.environ['edge_user_name'])
-        remove_all_iam_resources('edge', os.environ['edge_user_name'])
-        remove_sgroups(edge_conf['dataengine_instances_name'])
-        remove_sgroups(edge_conf['notebook_instance_name'])
-        remove_sgroups(edge_conf['instance_name'])
-        sys.exit(1)
-
-    try:
-        logging.info('[CREATING BUCKET POLICY FOR USER INSTANCES]')
-        print('[CREATING BUCKET POLICY FOR USER INSTANCES]')
-        params = '--bucket_name {} --ssn_bucket_name {} --shared_bucket_name {} --username {} --edge_role_name {} ' \
-                 '--notebook_role_name {} --service_base_name {} --region {} ' \
-                 '--user_predefined_s3_policies "{}"'.format(edge_conf['bucket_name'], edge_conf['ssn_bucket_name'],
-                                                             edge_conf['shared_bucket_name'],
-                                                             os.environ['edge_user_name'], edge_conf['role_name'],
-                                                             edge_conf['notebook_dataengine_role_name'],
-                                                             edge_conf['service_base_name'], edge_conf['region'],
-                                                             os.environ['aws_user_predefined_s3_policies'])
-        try:
-            local("~/scripts/{}.py {}".format('common_create_policy', params))
-        except:
-            traceback.print_exc()
-            raise Exception
-    except Exception as err:
-        print('Error: {0}'.format(err))
-        append_result("Failed to create bucket policy.", str(err))
-        remove_all_iam_resources('notebook', os.environ['edge_user_name'])
-        remove_all_iam_resources('edge', os.environ['edge_user_name'])
-        remove_sgroups(edge_conf['dataengine_instances_name'])
-        remove_sgroups(edge_conf['notebook_instance_name'])
-        remove_sgroups(edge_conf['instance_name'])
-        remove_s3('edge', os.environ['edge_user_name'])
-        sys.exit(1)
-
-    try:
-        logging.info('[CREATE EDGE INSTANCE]')
-        print('[CREATE EDGE INSTANCE]')
-        params = "--node_name {} --ami_id {} --instance_type {} --key_name {} --security_group_ids {} " \
-                 "--subnet_id {} --iam_profile {} --infra_tag_name {} --infra_tag_value {}" \
-            .format(edge_conf['instance_name'], edge_conf['ami_id'], edge_conf['instance_size'], edge_conf['key_name'],
-                    edge_group_id, edge_conf['public_subnet_id'], edge_conf['role_profile_name'],
-                    edge_conf['tag_name'], edge_conf['instance_name'])
-        try:
-            local("~/scripts/{}.py {}".format('common_create_instance', params))
-        except:
-            traceback.print_exc()
-            raise Exception
-
-    except Exception as err:
-        print('Error: {0}'.format(err))
-        append_result("Failed to create instance.", str(err))
-        remove_all_iam_resources('notebook', os.environ['edge_user_name'])
-        remove_all_iam_resources('edge', os.environ['edge_user_name'])
-        remove_sgroups(edge_conf['dataengine_instances_name'])
-        remove_sgroups(edge_conf['notebook_instance_name'])
-        remove_sgroups(edge_conf['instance_name'])
-        remove_s3('edge', os.environ['edge_user_name'])
-        sys.exit(1)
-
-    if edge_conf['network_type'] == 'public':
-        try:
-            logging.info('[ASSOCIATING ELASTIC IP]')
-            print('[ASSOCIATING ELASTIC IP]')
-            edge_conf['edge_id'] = get_instance_by_name(edge_conf['tag_name'], edge_conf['instance_name'])
-            try:
-                edge_conf['elastic_ip'] = os.environ['edge_elastic_ip']
-            except:
-                edge_conf['elastic_ip'] = 'None'
-            params = "--elastic_ip {} --edge_id {}  --infra_tag_name {} --infra_tag_value {}".format(
-                edge_conf['elastic_ip'], edge_conf['edge_id'], edge_conf['tag_name'], edge_conf['elastic_ip_name'])
-            try:
-                local("~/scripts/{}.py {}".format('edge_associate_elastic_ip', params))
-            except:
-                traceback.print_exc()
-                raise Exception
-        except Exception as err:
-            print('Error: {0}'.format(err))
-            append_result("Failed to associate elastic ip.", str(err))
-            try:
-                edge_conf['edge_public_ip'] = get_instance_ip_address(edge_conf['tag_name'],
-                                                                      edge_conf['instance_name']).get('Public')
-                edge_conf['allocation_id'] = get_allocation_id_by_elastic_ip(edge_conf['edge_public_ip'])
-            except:
-                print("No Elastic IPs to release!")
-            remove_ec2(edge_conf['tag_name'], edge_conf['instance_name'])
-            remove_all_iam_resources('notebook', os.environ['edge_user_name'])
-            remove_all_iam_resources('edge', os.environ['edge_user_name'])
-            remove_sgroups(edge_conf['dataengine_instances_name'])
-            remove_sgroups(edge_conf['notebook_instance_name'])
-            remove_sgroups(edge_conf['instance_name'])
-            remove_s3('edge', os.environ['edge_user_name'])
-            sys.exit(1)
diff --git a/infrastructure-provisioning/src/general/scripts/aws/edge_start.py b/infrastructure-provisioning/src/general/scripts/aws/edge_start.py
index c728591..5c43ff4 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/edge_start.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/edge_start.py
@@ -27,7 +27,7 @@
 
 
 if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -39,7 +39,7 @@
     print('Generating infrastructure names and tags')
     edge_conf = dict()
     edge_conf['service_base_name'] = os.environ['conf_service_base_name']
-    edge_conf['instance_name'] = edge_conf['service_base_name'] + "-" + os.environ['edge_user_name'] + '-edge'
+    edge_conf['instance_name'] = edge_conf['service_base_name'] + "-" + os.environ['project_name'] + '-edge'
     edge_conf['tag_name'] = edge_conf['service_base_name'] + '-Tag'
 
     logging.info('[START EDGE]')
diff --git a/infrastructure-provisioning/src/general/scripts/aws/edge_status.py b/infrastructure-provisioning/src/general/scripts/aws/edge_status.py
index 86ff6e3..e302bdc 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/edge_status.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/edge_status.py
@@ -30,7 +30,7 @@
 
 
 if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'], os.environ['request_id'])
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'], os.environ['request_id'])
     local_log_filepath = "/logs/edge/" + local_log_filename
     logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
                         level=logging.DEBUG,
diff --git a/infrastructure-provisioning/src/general/scripts/aws/edge_stop.py b/infrastructure-provisioning/src/general/scripts/aws/edge_stop.py
index dd52ff9..911046c 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/edge_stop.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/edge_stop.py
@@ -27,7 +27,7 @@
 
 
 if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -39,7 +39,7 @@
     print('Generating infrastructure names and tags')
     edge_conf = dict()
     edge_conf['service_base_name'] = os.environ['conf_service_base_name']
-    edge_conf['instance_name'] = edge_conf['service_base_name'] + "-" + os.environ['edge_user_name'] + '-edge'
+    edge_conf['instance_name'] = edge_conf['service_base_name'] + "-" + os.environ['project_name'] + '-edge'
     edge_conf['tag_name'] = edge_conf['service_base_name'] + '-Tag'
 
     logging.info('[STOP EDGE]')
diff --git a/infrastructure-provisioning/src/general/scripts/aws/jupyter_configure.py b/infrastructure-provisioning/src/general/scripts/aws/jupyter_configure.py
index 2b390b3..91f0871 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/jupyter_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/jupyter_configure.py
@@ -36,7 +36,7 @@
 
 
 if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -51,18 +51,18 @@
     notebook_config['service_base_name'] = os.environ['conf_service_base_name']
     notebook_config['instance_type'] = os.environ['aws_notebook_instance_type']
     notebook_config['key_name'] = os.environ['conf_key_name']
-    notebook_config['user_keyname'] = os.environ['edge_user_name']
+    notebook_config['user_keyname'] = os.environ['project_name']
     notebook_config['network_type'] = os.environ['conf_network_type']
     notebook_config['instance_name'] = '{}-{}-nb-{}-{}'.format(notebook_config['service_base_name'],
-                                                               os.environ['edge_user_name'],
+                                                               os.environ['project_name'],
                                                                notebook_config['exploratory_name'], args.uuid)
     notebook_config['expected_image_name'] = '{}-{}-notebook-image'.format(notebook_config['service_base_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'].lower().replace('-', '_'), os.environ['edge_user_name'])
+        .format(notebook_config['service_base_name'].lower().replace('-', '_'), os.environ['project_name'])
     notebook_config['security_group_name'] = '{}-{}-nb-SG'.format(notebook_config['service_base_name'],
-                                                                  os.environ['edge_user_name'])
+                                                                  os.environ['project_name'])
     notebook_config['tag_name'] = '{}-Tag'.format(notebook_config['service_base_name'])
     notebook_config['dlab_ssh_user'] = os.environ['conf_os_user']
     notebook_config['shared_image_enabled'] = os.environ['conf_shared_image_enabled']
@@ -70,7 +70,7 @@
 
     # generating variables regarding EDGE proxy on Notebook instance
     instance_hostname = get_instance_hostname(notebook_config['tag_name'], notebook_config['instance_name'])
-    edge_instance_name = os.environ['conf_service_base_name'] + "-" + os.environ['edge_user_name'] + '-edge'
+    edge_instance_name = os.environ['conf_service_base_name'] + "-" + os.environ['project_name'] + '-edge'
     edge_instance_hostname = get_instance_hostname(notebook_config['tag_name'], edge_instance_name)
     edge_instance_private_ip = get_instance_ip_address(notebook_config['tag_name'], edge_instance_name).get('Private')
     if notebook_config['network_type'] == 'private':
diff --git a/infrastructure-provisioning/src/general/scripts/aws/jupyter_dataengine-service_create_configs.py b/infrastructure-provisioning/src/general/scripts/aws/jupyter_dataengine-service_create_configs.py
index 937ca5b..9af6935 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/jupyter_dataengine-service_create_configs.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/jupyter_dataengine-service_create_configs.py
@@ -45,7 +45,7 @@
 parser.add_argument('--hadoop_version', type=str, default='')
 parser.add_argument('--region', type=str, default='')
 parser.add_argument('--excluded_lines', type=str, default='')
-parser.add_argument('--user_name', type=str, default='')
+parser.add_argument('--project_name', type=str, default='')
 parser.add_argument('--os_user', type=str, default='')
 parser.add_argument('--pip_mirror', type=str, default='')
 parser.add_argument('--numpy_version', type=str, default='')
@@ -175,7 +175,7 @@
         yarn(args, yarn_dir)
         install_emr_spark(args)
         pyspark_kernel(kernels_dir, args.emr_version, args.cluster_name, args.spark_version, args.bucket,
-                       args.user_name, args.region, args.os_user, args.application, args.pip_mirror, args.numpy_version)
+                       args.project_name, args.region, args.os_user, args.application, args.pip_mirror, args.numpy_version)
         toree_kernel(args)
         if args.r_enabled == 'true':
             r_kernel(args)
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 294f9d2..6900a6a 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
@@ -37,7 +37,7 @@
 parser.add_argument('--notebook_ip', type=str, default='')
 parser.add_argument('--scala_version', type=str, default='')
 parser.add_argument('--emr_excluded_spark_properties', 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='')
@@ -82,5 +82,5 @@
     sudo("/usr/bin/python /usr/local/bin/jupyter_dataengine-service_create_configs.py --bucket " + args.bucket +
          " --cluster_name " + args.cluster_name + " --emr_version " + args.emr_version + " --spark_version " +
          spark_version + " --hadoop_version " + hadoop_version + " --region " + args.region + " --excluded_lines '"
-         + args.emr_excluded_spark_properties + "' --user_name " + args.edge_user_name + " --os_user " + args.os_user +
+         + args.emr_excluded_spark_properties + "' --project_name " + args.project_name + " --os_user " + args.os_user +
          " --pip_mirror " + args.pip_mirror + " --numpy_version " + numpy_version + " --application " + args.application + " --r_enabled " + r_enabled)
diff --git a/infrastructure-provisioning/src/general/scripts/aws/project_prepare.py b/infrastructure-provisioning/src/general/scripts/aws/project_prepare.py
new file mode 100644
index 0000000..2e76c81
--- /dev/null
+++ b/infrastructure-provisioning/src/general/scripts/aws/project_prepare.py
@@ -0,0 +1,593 @@
+#!/usr/bin/python
+
+# *****************************************************************************
+#
+# 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 json
+from dlab.fab import *
+from dlab.meta_lib import *
+import sys, time, os
+from dlab.actions_lib import *
+import traceback
+
+
+if __name__ == "__main__":
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/project/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    create_aws_config_files()
+    print('Generating infrastructure names and tags')
+    project_conf = dict()
+    project_conf['service_base_name'] = os.environ['conf_service_base_name']
+    project_conf['project_tag'] = os.environ['project_name']
+    project_conf['custom_tag'] = os.environ['project_tag']
+    project_conf['key_name'] = os.environ['conf_key_name']
+    project_conf['public_subnet_id'] = os.environ['aws_subnet_id']
+    project_conf['vpc_id'] = os.environ['aws_vpc_id']
+    project_conf['region'] = os.environ['aws_region']
+    project_conf['ami_id'] = get_ami_id(os.environ['aws_{}_image_name'.format(os.environ['conf_os_family'])])
+    project_conf['instance_size'] = os.environ['aws_edge_instance_size']
+    project_conf['sg_ids'] = os.environ['aws_security_groups_ids']
+    project_conf['edge_instance_name'] = '{}-{}-edge'.format(project_conf['service_base_name'], os.environ['project_name'])
+    project_conf['tag_name'] = '{}-Tag'.format(project_conf['service_base_name'])
+    project_conf['bucket_name_tag'] = '{}-{}-bucket'.format(project_conf['service_base_name'],
+                                                     os.environ['project_name'])
+    project_conf['bucket_name'] = project_conf['bucket_name_tag'].lower().replace('_', '-')
+    project_conf['ssn_bucket_name'] = '{}-ssn-bucket'.format(project_conf['service_base_name']).lower().replace('_', '-')
+    project_conf['shared_bucket_name'] = '{}-shared-bucket'.format(project_conf['service_base_name']).lower().replace('_',
+                                                                                                                '-')
+    project_conf['edge_role_name'] = '{}-{}-edge-Role'.format(project_conf['service_base_name'].lower().replace('-', '_'),
+                                                      os.environ['project_name'])
+    project_conf['edge_role_profile_name'] = '{}-{}-edge-Profile'.format(project_conf['service_base_name'].lower().replace('-',
+                                                                                                                '_'),
+                                                                 os.environ['project_name'])
+    project_conf['edge_policy_name'] = '{}-{}-edge-Policy'.format(project_conf['service_base_name'].lower().replace('-', '_'),
+                                                          os.environ['project_name'])
+    project_conf['edge_security_group_name'] = '{}-SG'.format(project_conf['edge_instance_name'])
+    project_conf['notebook_instance_name'] = '{}-{}-nb'.format(project_conf['service_base_name'],
+                                                            os.environ['project_name'])
+    project_conf['dataengine_instances_name'] = '{}-{}-dataengine' \
+        .format(project_conf['service_base_name'], os.environ['project_name'])
+    project_conf['notebook_dataengine_role_name'] = '{}-{}-nb-de-Role' \
+        .format(project_conf['service_base_name'].lower().replace('-', '_'), os.environ['project_name'])
+    project_conf['notebook_dataengine_policy_name'] = '{}-{}-nb-de-Policy' \
+        .format(project_conf['service_base_name'].lower().replace('-', '_'), os.environ['project_name'])
+    project_conf['notebook_dataengine_role_profile_name'] = '{}-{}-nb-de-Profile' \
+        .format(project_conf['service_base_name'].lower().replace('-', '_'), os.environ['project_name'])
+    project_conf['notebook_security_group_name'] = '{}-{}-nb-SG'.format(project_conf['service_base_name'],
+                                                                     os.environ['project_name'])
+    project_conf['private_subnet_prefix'] = os.environ['aws_private_subnet_prefix']
+    project_conf['private_subnet_name'] = '{0}-{1}-subnet'.format(project_conf['service_base_name'],
+                                                               os.environ['project_name'])
+    project_conf['dataengine_master_security_group_name'] = '{}-{}-dataengine-master-sg' \
+        .format(project_conf['service_base_name'], os.environ['project_name'])
+    project_conf['dataengine_slave_security_group_name'] = '{}-{}-dataengine-slave-sg' \
+        .format(project_conf['service_base_name'], os.environ['project_name'])
+    project_conf['allowed_ip_cidr'] = list()
+    for cidr in os.environ['conf_allowed_ip_cidr'].split(','):
+        project_conf['allowed_ip_cidr'].append({"CidrIp": cidr.replace(' ','')})
+    project_conf['network_type'] = os.environ['conf_network_type']
+    project_conf['all_ip_cidr'] = '0.0.0.0/0'
+    project_conf['zone'] = os.environ['aws_region'] + os.environ['aws_zone']
+    project_conf['elastic_ip_name'] = '{0}-{1}-edge-EIP'.format(project_conf['service_base_name'],
+                                                             os.environ['project_name'])
+    if 'aws_user_predefined_s3_policies' not in os.environ:
+        os.environ['aws_user_predefined_s3_policies'] = 'None'
+
+    try:
+        if os.environ['conf_user_subnets_range'] == '':
+            raise KeyError
+    except KeyError:
+        os.environ['conf_user_subnets_range'] = ''
+
+    # FUSE in case of absence of user's key
+    try:
+        project_conf['user_key'] = os.environ['key']
+    except KeyError:
+        print("ADMINSs PUBLIC KEY DOES NOT UPLOADED")
+        sys.exit(1)
+
+    print("Will create exploratory environment with edge node as access point as following: {}".
+          format(json.dumps(project_conf, sort_keys=True, indent=4, separators=(',', ': '))))
+    logging.info(json.dumps(project_conf))
+
+    try:
+        project_conf['vpc2_id'] = os.environ['aws_vpc2_id']
+        project_conf['tag_name'] = '{}-secondary-Tag'.format(project_conf['service_base_name'])
+    except KeyError:
+        project_conf['vpc2_id'] = project_conf['vpc_id']
+
+    try:
+        logging.info('[CREATE SUBNET]')
+        print('[CREATE SUBNET]')
+        params = "--vpc_id '{}' --infra_tag_name {} --infra_tag_value {} --prefix {} " \
+                 "--user_subnets_range '{}' --subnet_name {} --zone {}".format(
+            project_conf['vpc2_id'], project_conf['tag_name'], project_conf['service_base_name'],
+            project_conf['private_subnet_prefix'], os.environ['conf_user_subnets_range'],
+            project_conf['private_subnet_name'],
+            project_conf['zone'])
+        try:
+            local("~/scripts/{}.py {}".format('common_create_subnet', params))
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        append_result("Failed to create subnet.", str(err))
+        sys.exit(1)
+
+    tag = {"Key": project_conf['tag_name'],
+           "Value": "{0}-{1}-subnet".format(project_conf['service_base_name'], project_conf['project_tag'])}
+    project_conf['private_subnet_cidr'] = get_subnet_by_tag(tag)
+    project_tag = {"Key": 'project_tag', "Value": project_conf['project_tag']}
+    subnet_id = get_subnet_by_cidr(project_conf['private_subnet_cidr'])
+    print('subnet id: {}'.format(subnet_id))
+    create_tag(subnet_id, project_tag)
+    print('NEW SUBNET CIDR CREATED: {}'.format(project_conf['private_subnet_cidr']))
+
+    try:
+        logging.info('[CREATE EDGE ROLES]')
+        print('[CREATE EDGE ROLES]')
+        params = "--role_name {} --role_profile_name {} --policy_name {} --region {} --infra_tag_name {} " \
+                 "--infra_tag_value {}" \
+                 .format(project_conf['edge_role_name'], project_conf['edge_role_profile_name'],
+                         project_conf['edge_policy_name'], os.environ['aws_region'], project_conf['tag_name'],
+                         project_conf['service_base_name'])
+        try:
+            local("~/scripts/{}.py {}".format('common_create_role_policy', params))
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        append_result("Failed to creating roles.", str(err))
+        sys.exit(1)
+
+    try:
+        logging.info('[CREATE BACKEND (NOTEBOOK) ROLES]')
+        print('[CREATE BACKEND (NOTEBOOK) ROLES]')
+        params = "--role_name {} --role_profile_name {} --policy_name {} --region {} --infra_tag_name {} " \
+                 "--infra_tag_value {}" \
+                 .format(project_conf['notebook_dataengine_role_name'], project_conf['notebook_dataengine_role_profile_name'],
+                         project_conf['notebook_dataengine_policy_name'], os.environ['aws_region'], project_conf['tag_name'],
+                         project_conf['service_base_name'])
+        try:
+            local("~/scripts/{}.py {}".format('common_create_role_policy', params))
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        append_result("Failed to creating roles.", str(err))
+        remove_all_iam_resources('edge', os.environ['project_name'])
+        sys.exit(1)
+
+    try:
+        logging.info('[CREATE SECURITY GROUP FOR EDGE NODE]')
+        print('[CREATE SECURITY GROUPS FOR EDGE]')
+        edge_sg_ingress = format_sg([
+            {
+                "IpProtocol": "-1",
+                "IpRanges": [{"CidrIp": project_conf['private_subnet_cidr']}],
+                "UserIdGroupPairs": [], "PrefixListIds": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 22,
+                "IpRanges": project_conf['allowed_ip_cidr'],
+                "ToPort": 22, "IpProtocol": "tcp", "UserIdGroupPairs": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 3128,
+                "IpRanges": project_conf['allowed_ip_cidr'],
+                "ToPort": 3128, "IpProtocol": "tcp", "UserIdGroupPairs": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 80,
+                "IpRanges": project_conf['allowed_ip_cidr'],
+                "ToPort": 80, "IpProtocol": "tcp", "UserIdGroupPairs": []
+            },
+            {
+                "IpProtocol": "-1",
+                "IpRanges": [{"CidrIp": get_instance_ip_address(project_conf['tag_name'], '{}-ssn'.format(
+                    project_conf['service_base_name'])).get('Private') + "/32"}],
+                "UserIdGroupPairs": [],
+                "PrefixListIds": []
+            }
+        ])
+        edge_sg_egress = format_sg([
+            {
+                "PrefixListIds": [],
+                "FromPort": 22,
+                "IpRanges": [{"CidrIp": project_conf['private_subnet_cidr']}],
+                "ToPort": 22, "IpProtocol": "tcp", "UserIdGroupPairs": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 8888,
+                "IpRanges": [{"CidrIp": project_conf['private_subnet_cidr']}],
+                "ToPort": 8888, "IpProtocol": "tcp", "UserIdGroupPairs": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 8080,
+                "IpRanges": [{"CidrIp": project_conf['private_subnet_cidr']}],
+                "ToPort": 8080, "IpProtocol": "tcp", "UserIdGroupPairs": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 8787,
+                "IpRanges": [{"CidrIp": project_conf['private_subnet_cidr']}],
+                "ToPort": 8787, "IpProtocol": "tcp", "UserIdGroupPairs": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 6006,
+                "IpRanges": [{"CidrIp": project_conf['private_subnet_cidr']}],
+                "ToPort": 6006, "IpProtocol": "tcp", "UserIdGroupPairs": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 20888,
+                "IpRanges": [{"CidrIp": project_conf['private_subnet_cidr']}],
+                "ToPort": 20888, "IpProtocol": "tcp", "UserIdGroupPairs": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 8042,
+                "IpRanges": [{"CidrIp": project_conf['private_subnet_cidr']}],
+                "ToPort": 8042, "IpProtocol": "tcp", "UserIdGroupPairs": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 8088,
+                "IpRanges": [{"CidrIp": project_conf['private_subnet_cidr']}],
+                "ToPort": 8088, "IpProtocol": "tcp", "UserIdGroupPairs": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 8081,
+                "IpRanges": [{"CidrIp": project_conf['private_subnet_cidr']}],
+                "ToPort": 8081, "IpProtocol": "tcp", "UserIdGroupPairs": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 4040,
+                "IpRanges": [{"CidrIp": project_conf['private_subnet_cidr']}],
+                "ToPort": 4140, "IpProtocol": "tcp", "UserIdGroupPairs": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 18080,
+                "IpRanges": [{"CidrIp": project_conf['private_subnet_cidr']}],
+                "ToPort": 18080, "IpProtocol": "tcp", "UserIdGroupPairs": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 50070,
+                "IpRanges": [{"CidrIp": project_conf['private_subnet_cidr']}],
+                "ToPort": 50070, "IpProtocol": "tcp", "UserIdGroupPairs": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 53,
+                "IpRanges": [{"CidrIp": project_conf['all_ip_cidr']}],
+                "ToPort": 53, "IpProtocol": "udp", "UserIdGroupPairs": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 80,
+                "IpRanges": [{"CidrIp": project_conf['all_ip_cidr']}],
+                "ToPort": 80, "IpProtocol": "tcp", "UserIdGroupPairs": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 123,
+                "IpRanges": [{"CidrIp": project_conf['all_ip_cidr']}],
+                "ToPort": 123, "IpProtocol": "udp", "UserIdGroupPairs": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 443,
+                "IpRanges": [{"CidrIp": project_conf['all_ip_cidr']}],
+                "ToPort": 443, "IpProtocol": "tcp", "UserIdGroupPairs": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 8085,
+                "IpRanges": [{"CidrIp": project_conf['private_subnet_cidr']}],
+                "ToPort": 8085, "IpProtocol": "tcp", "UserIdGroupPairs": []
+            },
+            {
+                "PrefixListIds": [],
+                "FromPort": 389,
+                "IpRanges": [{"CidrIp": project_conf['all_ip_cidr']}],
+                "ToPort": 389, "IpProtocol": "tcp", "UserIdGroupPairs": []
+            }
+        ])
+        params = "--name {} --vpc_id {} --security_group_rules '{}' --infra_tag_name {} --infra_tag_value {} \
+            --egress '{}' --force {} --nb_sg_name {} --resource {}".\
+            format(project_conf['edge_security_group_name'], project_conf['vpc_id'], json.dumps(edge_sg_ingress),
+                   project_conf['service_base_name'], project_conf['edge_instance_name'], json.dumps(edge_sg_egress),
+                   True, project_conf['notebook_instance_name'], 'edge')
+        try:
+            local("~/scripts/{}.py {}".format('common_create_security_group', params))
+        except Exception as err:
+            traceback.print_exc()
+            append_result("Failed creating security group for edge node.", str(err))
+            raise Exception
+
+        with hide('stderr', 'running', 'warnings'):
+            print('Waiting for changes to propagate')
+            time.sleep(10)
+    except:
+        remove_all_iam_resources('notebook', os.environ['project_name'])
+        remove_all_iam_resources('edge', os.environ['project_name'])
+        sys.exit(1)
+
+    try:
+        logging.info('[CREATE SECURITY GROUP FOR PRIVATE SUBNET]')
+        print('[CREATE SECURITY GROUP FOR PRIVATE SUBNET]')
+        project_group_id = check_security_group(project_conf['edge_security_group_name'])
+        sg_list = project_conf['sg_ids'].replace(" ", "").split(',')
+        rules_list = []
+        for i in sg_list:
+            rules_list.append({"GroupId": i})
+        private_sg_ingress = format_sg([
+            {
+                "IpProtocol": "-1",
+                "IpRanges": [],
+                "UserIdGroupPairs": [{"GroupId": project_group_id}],
+                "PrefixListIds": []
+            },
+            {
+                "IpProtocol": "-1",
+                "IpRanges": [{"CidrIp": project_conf['private_subnet_cidr']}],
+                "UserIdGroupPairs": [],
+                "PrefixListIds": []
+            },
+            {
+                "IpProtocol": "-1",
+                "IpRanges": [{"CidrIp": get_instance_ip_address(project_conf['tag_name'], '{}-ssn'.format(
+                    project_conf['service_base_name'])).get('Private') + "/32"}],
+                "UserIdGroupPairs": [],
+                "PrefixListIds": []
+            }
+        ])
+
+        private_sg_egress = format_sg([
+            {
+                "IpProtocol": "-1",
+                "IpRanges": [{"CidrIp": project_conf['private_subnet_cidr']}],
+                "UserIdGroupPairs": [],
+                "PrefixListIds": []
+            },
+            {
+                "IpProtocol": "-1",
+                "IpRanges": [{"CidrIp": get_instance_ip_address(project_conf['tag_name'], '{}-ssn'.format(
+                    project_conf['service_base_name'])).get('Private') + "/32"}],
+                "UserIdGroupPairs": [],
+                "PrefixListIds": [],
+            },
+            {
+                "IpProtocol": "-1",
+                "IpRanges": [],
+                "UserIdGroupPairs": [{"GroupId": project_group_id}],
+                "PrefixListIds": []
+            },
+            {
+                "IpProtocol": "tcp",
+                "IpRanges": [{"CidrIp": project_conf['all_ip_cidr']}],
+                "FromPort": 443,
+                "ToPort": 443,
+                "UserIdGroupPairs": [],
+                "PrefixListIds": [],
+            }
+        ])
+
+        params = "--name {} --vpc_id {} --security_group_rules '{}' --egress '{}' --infra_tag_name {} " \
+                 "--infra_tag_value {} --force {}".format(project_conf['notebook_security_group_name'],
+                                                          project_conf['vpc2_id'], json.dumps(private_sg_ingress),
+                                                          json.dumps(private_sg_egress), project_conf['service_base_name'],
+                                                          project_conf['notebook_instance_name'], True)
+        try:
+            local("~/scripts/{}.py {}".format('common_create_security_group', params))
+        except:
+            traceback.print_exc()
+            raise Exception
+
+        with hide('stderr', 'running', 'warnings'):
+            print('Waiting for changes to propagate')
+            time.sleep(10)
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        append_result("Failed creating security group for private subnet.", str(err))
+        remove_all_iam_resources('notebook', os.environ['project_name'])
+        remove_all_iam_resources('edge', os.environ['project_name'])
+        remove_sgroups(project_conf['notebook_instance_name'])
+        remove_sgroups(project_conf['edge_instance_name'])
+        sys.exit(1)
+
+    logging.info('[CREATING SECURITY GROUPS FOR MASTER NODE]')
+    print("[CREATING SECURITY GROUPS FOR MASTER NODE]")
+    try:
+        params = "--name {} --vpc_id {} --security_group_rules '{}' --egress '{}' --infra_tag_name {} " \
+                 "--infra_tag_value {} --force {}".format(project_conf['dataengine_master_security_group_name'],
+                                                          project_conf['vpc2_id'], json.dumps(private_sg_ingress),
+                                                          json.dumps(private_sg_egress), project_conf['service_base_name'],
+                                                          project_conf['dataengine_instances_name'], True)
+        try:
+            local("~/scripts/{}.py {}".format('common_create_security_group', params))
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        append_result("Failed to create sg.", str(err))
+        remove_all_iam_resources('notebook', os.environ['project_name'])
+        remove_all_iam_resources('edge', os.environ['project_name'])
+        remove_sgroups(project_conf['notebook_instance_name'])
+        remove_sgroups(project_conf['edge_instance_name'])
+        sys.exit(1)
+
+    logging.info('[CREATING SECURITY GROUPS FOR SLAVE NODES]')
+    print("[CREATING SECURITY GROUPS FOR SLAVE NODES]")
+    try:
+        params = "--name {} --vpc_id {} --security_group_rules '{}' --egress '{}' --infra_tag_name {} " \
+                 "--infra_tag_value {} --force {}".format(project_conf['dataengine_slave_security_group_name'],
+                                                          project_conf['vpc2_id'], json.dumps(private_sg_ingress),
+                                                          json.dumps(private_sg_egress), project_conf['service_base_name'],
+                                                          project_conf['dataengine_instances_name'], True)
+        try:
+            local("~/scripts/{}.py {}".format('common_create_security_group', params))
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        append_result("Failed to create bucket.", str(err))
+        remove_all_iam_resources('notebook', os.environ['project_name'])
+        remove_all_iam_resources('edge', os.environ['project_name'])
+        remove_sgroups(project_conf['dataengine_instances_name'])
+        remove_sgroups(project_conf['notebook_instance_name'])
+        remove_sgroups(project_conf['edge_instance_name'])
+        sys.exit(1)
+
+    try:
+        logging.info('[CREATE BUCKETS]')
+        print('[CREATE BUCKETS]')
+        params = "--bucket_name {} --infra_tag_name {} --infra_tag_value {} --region {} --bucket_name_tag {}" \
+                 .format(project_conf['bucket_name'], project_conf['tag_name'], project_conf['bucket_name'],
+                         project_conf['region'], project_conf['bucket_name_tag'])
+        try:
+            os.environ['conf_additional_tags'] = os.environ['conf_additional_tags'] + ';project_tag:{}'.format(
+                project_conf['project_tag'])
+        except KeyError:
+            os.environ['conf_additional_tags'] = 'project_tag:{}'.format(project_conf['project_tag'])
+        print('Additional tags will be added: {}'.format(os.environ['conf_additional_tags']))
+        try:
+            local("~/scripts/{}.py {}".format('common_create_bucket', params))
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        append_result("Failed to create bucket.", str(err))
+        remove_all_iam_resources('notebook', os.environ['project_name'])
+        remove_all_iam_resources('edge', os.environ['project_name'])
+        remove_sgroups(project_conf['dataengine_instances_name'])
+        remove_sgroups(project_conf['notebook_instance_name'])
+        remove_sgroups(project_conf['edge_instance_name'])
+        sys.exit(1)
+
+    try:
+        logging.info('[CREATING BUCKET POLICY FOR PROJECT INSTANCES]')
+        print('[CREATING BUCKET POLICY FOR USER INSTANCES]')
+        params = '--bucket_name {} --ssn_bucket_name {} --shared_bucket_name {} --username {} --edge_role_name {} ' \
+                 '--notebook_role_name {} --service_base_name {} --region {} ' \
+                 '--user_predefined_s3_policies "{}"'.format(project_conf['bucket_name'], project_conf['ssn_bucket_name'],
+                                                             project_conf['shared_bucket_name'],
+                                                             os.environ['project_name'], project_conf['edge_role_name'],
+                                                             project_conf['notebook_dataengine_role_name'],
+                                                             project_conf['service_base_name'], project_conf['region'],
+                                                             os.environ['aws_user_predefined_s3_policies'])
+        try:
+            local("~/scripts/{}.py {}".format('common_create_policy', params))
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        append_result("Failed to create bucket policy.", str(err))
+        remove_all_iam_resources('notebook', os.environ['project_name'])
+        remove_all_iam_resources('edge', os.environ['project_name'])
+        remove_sgroups(project_conf['dataengine_instances_name'])
+        remove_sgroups(project_conf['notebook_instance_name'])
+        remove_sgroups(project_conf['edge_instance_name'])
+        remove_s3('edge', os.environ['project_name'])
+        sys.exit(1)
+
+    try:
+        logging.info('[CREATE EDGE INSTANCE]')
+        print('[CREATE EDGE INSTANCE]')
+        params = "--node_name {} --ami_id {} --instance_type {} --key_name {} --security_group_ids {} " \
+                 "--subnet_id {} --iam_profile {} --infra_tag_name {} --infra_tag_value {}" \
+            .format(project_conf['edge_instance_name'], project_conf['ami_id'], project_conf['instance_size'], project_conf['key_name'],
+                    project_group_id, project_conf['public_subnet_id'], project_conf['edge_role_profile_name'],
+                    project_conf['tag_name'], project_conf['edge_instance_name'])
+        try:
+            local("~/scripts/{}.py {}".format('common_create_instance', params))
+            edge_instance = get_instance_by_name(project_conf['tag_name'], project_conf['edge_instance_name'])
+            create_tag(edge_instance, project_tag)
+        except:
+            traceback.print_exc()
+            raise Exception
+
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        append_result("Failed to create instance.", str(err))
+        remove_all_iam_resources('notebook', os.environ['project_name'])
+        remove_all_iam_resources('edge', os.environ['project_name'])
+        remove_sgroups(project_conf['dataengine_instances_name'])
+        remove_sgroups(project_conf['notebook_instance_name'])
+        remove_sgroups(project_conf['edge_instance_name'])
+        remove_s3('edge', os.environ['project_name'])
+        sys.exit(1)
+
+    if project_conf['network_type'] == 'public':
+        try:
+            logging.info('[ASSOCIATING ELASTIC IP]')
+            print('[ASSOCIATING ELASTIC IP]')
+            project_conf['edge_id'] = get_instance_by_name(project_conf['tag_name'], project_conf['edge_instance_name'])
+            try:
+                project_conf['elastic_ip'] = os.environ['edge_elastic_ip']
+            except:
+                project_conf['elastic_ip'] = 'None'
+            params = "--elastic_ip {} --edge_id {}  --infra_tag_name {} --infra_tag_value {}".format(
+                project_conf['elastic_ip'], project_conf['edge_id'], project_conf['tag_name'], project_conf['elastic_ip_name'])
+            try:
+                local("~/scripts/{}.py {}".format('edge_associate_elastic_ip', params))
+            except:
+                traceback.print_exc()
+                raise Exception
+        except Exception as err:
+            print('Error: {0}'.format(err))
+            append_result("Failed to associate elastic ip.", str(err))
+            try:
+                project_conf['edge_public_ip'] = get_instance_ip_address(project_conf['tag_name'],
+                                                                      project_conf['edge_instance_name']).get('Public')
+                project_conf['allocation_id'] = get_allocation_id_by_elastic_ip(project_conf['edge_public_ip'])
+            except:
+                print("No Elastic IPs to release!")
+            remove_ec2(project_conf['tag_name'], project_conf['edge_instance_name'])
+            remove_all_iam_resources('notebook', os.environ['project_name'])
+            remove_all_iam_resources('edge', os.environ['project_name'])
+            remove_sgroups(project_conf['dataengine_instances_name'])
+            remove_sgroups(project_conf['notebook_instance_name'])
+            remove_sgroups(project_conf['edge_instance_name'])
+            remove_s3('edge', os.environ['project_name'])
+            sys.exit(1)
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/general/scripts/aws/edge_terminate.py b/infrastructure-provisioning/src/general/scripts/aws/project_terminate.py
similarity index 65%
rename from infrastructure-provisioning/src/general/scripts/aws/edge_terminate.py
rename to infrastructure-provisioning/src/general/scripts/aws/project_terminate.py
index 26be0b8..ec32b58 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/edge_terminate.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/project_terminate.py
@@ -28,7 +28,7 @@
 from dlab.actions_lib import *
 
 
-def terminate_edge_node(tag_name, user_name, tag_value, nb_sg, edge_sg, de_sg, emr_sg):
+def terminate_edge_node(tag_name, project_tag, tag_value, nb_sg, edge_sg, de_sg, emr_sg):
     print('Terminating EMR cluster')
     try:
         clusters_list = get_emr_list(tag_name)
@@ -55,14 +55,14 @@
 
     print("Removing s3 bucket")
     try:
-        remove_s3('edge', user_name)
+        remove_s3('edge', project_tag)
     except:
         sys.exit(1)
 
     print("Removing IAM roles and profiles")
     try:
-        remove_all_iam_resources('notebook', user_name)
-        remove_all_iam_resources('edge', user_name)
+        remove_all_iam_resources('notebook', project_tag)
+        remove_all_iam_resources('edge', project_tag)
     except:
         sys.exit(1)
 
@@ -83,8 +83,8 @@
 
 
 if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'], os.environ['request_id'])
-    local_log_filepath = "/logs/edge/" + local_log_filename
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'], os.environ['request_id'])
+    local_log_filepath = "/logs/project/" + local_log_filename
     logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
                         level=logging.DEBUG,
                         filename=local_log_filepath)
@@ -92,35 +92,35 @@
     # generating variables dictionary
     create_aws_config_files()
     print('Generating infrastructure names and tags')
-    edge_conf = dict()
-    edge_conf['service_base_name'] = os.environ['conf_service_base_name']
-    edge_conf['user_name'] = os.environ['edge_user_name']
-    edge_conf['tag_name'] = edge_conf['service_base_name'] + '-Tag'
-    edge_conf['tag_value'] = edge_conf['service_base_name'] + "-" + os.environ['edge_user_name'] + '-*'
-    edge_conf['edge_sg'] = edge_conf['service_base_name'] + "-" + os.environ['edge_user_name'] + '-edge'
-    edge_conf['nb_sg'] = edge_conf['service_base_name'] + "-" + os.environ['edge_user_name'] + '-nb'
-    edge_conf['edge_instance_name'] = edge_conf['service_base_name'] + "-" + os.environ['edge_user_name'] + '-edge'
-    edge_conf['de_sg'] = edge_conf['service_base_name'] + "-" + edge_conf['user_name'] + \
+    project_conf = dict()
+    project_conf['service_base_name'] = os.environ['conf_service_base_name']
+    project_conf['project_tag'] = os.environ['project_name']
+    project_conf['tag_name'] = project_conf['service_base_name'] + '-Tag'
+    project_conf['tag_value'] = project_conf['service_base_name'] + "-" + os.environ['project_name'] + '-*'
+    project_conf['edge_sg'] = project_conf['service_base_name'] + "-" + os.environ['project_name'] + '-edge'
+    project_conf['nb_sg'] = project_conf['service_base_name'] + "-" + os.environ['project_name'] + '-nb'
+    project_conf['edge_instance_name'] = project_conf['service_base_name'] + "-" + os.environ['project_name'] + '-edge'
+    project_conf['de_sg'] = project_conf['service_base_name'] + "-" + project_conf['project_tag'] + \
                                              '-dataengine*'
-    edge_conf['emr_sg'] = edge_conf['service_base_name'] + "-" + edge_conf['user_name'] + '-des-*'
+    project_conf['emr_sg'] = project_conf['service_base_name'] + "-" + project_conf['project_tag'] + '-des-*'
 
     try:
-        logging.info('[TERMINATE EDGE]')
-        print('[TERMINATE EDGE]')
+        logging.info('[TERMINATE PROJECT]')
+        print('[TERMINATE PROJECT]')
         try:
-            terminate_edge_node(edge_conf['tag_name'], edge_conf['user_name'], edge_conf['tag_value'],
-                                edge_conf['nb_sg'], edge_conf['edge_sg'], edge_conf['de_sg'], edge_conf['emr_sg'])
+            terminate_edge_node(project_conf['tag_name'], project_conf['project_tag'], project_conf['tag_value'],
+                                project_conf['nb_sg'], project_conf['edge_sg'], project_conf['de_sg'], project_conf['emr_sg'])
         except Exception as err:
             traceback.print_exc()
-            append_result("Failed to terminate edge.", str(err))
+            append_result("Failed to terminate project.", str(err))
     except Exception as err:
         print('Error: {0}'.format(err))
         sys.exit(1)
 
     try:
         with open("/root/result.json", 'w') as result:
-            res = {"service_base_name": edge_conf['service_base_name'],
-                   "user_name": edge_conf['user_name'],
+            res = {"service_base_name": project_conf['service_base_name'],
+                   "project_tag": project_conf['project_tag'],
                    "Action": "Terminate edge node"}
             print(json.dumps(res))
             result.write(json.dumps(res))
diff --git a/infrastructure-provisioning/src/general/scripts/aws/rstudio_configure.py b/infrastructure-provisioning/src/general/scripts/aws/rstudio_configure.py
index e0b046c..b49ca4c 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/rstudio_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/rstudio_configure.py
@@ -37,7 +37,7 @@
 
 if __name__ == "__main__":
     instance_class = 'notebook'
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -52,18 +52,18 @@
     notebook_config['service_base_name'] = os.environ['conf_service_base_name']
     notebook_config['instance_type'] = os.environ['aws_notebook_instance_type']
     notebook_config['key_name'] = os.environ['conf_key_name']
-    notebook_config['user_keyname'] = os.environ['edge_user_name']
+    notebook_config['user_keyname'] = os.environ['project_name']
     notebook_config['network_type'] = os.environ['conf_network_type']
     notebook_config['instance_name'] = '{}-{}-nb-{}-{}'.format(notebook_config['service_base_name'],
-                                                               os.environ['edge_user_name'],
+                                                               os.environ['project_name'],
                                                                notebook_config['exploratory_name'], args.uuid)
     notebook_config['expected_image_name'] = '{}-{}-notebook-image'.format(notebook_config['service_base_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'].lower().replace('-', '_'), os.environ['edge_user_name'])
+        .format(notebook_config['service_base_name'].lower().replace('-', '_'), os.environ['project_name'])
     notebook_config['security_group_name'] = '{}-{}-nb-SG'.format(notebook_config['service_base_name'],
-                                                                  os.environ['edge_user_name'])
+                                                                  os.environ['project_name'])
     notebook_config['tag_name'] = '{}-Tag'.format(notebook_config['service_base_name'])
     notebook_config['rstudio_pass'] = id_generator()
     notebook_config['dlab_ssh_user'] = os.environ['conf_os_user']
@@ -72,7 +72,7 @@
 
     # generating variables regarding EDGE proxy on Notebook instance
     instance_hostname = get_instance_hostname(notebook_config['tag_name'], notebook_config['instance_name'])
-    edge_instance_name = os.environ['conf_service_base_name'] + "-" + os.environ['edge_user_name'] + '-edge'
+    edge_instance_name = os.environ['conf_service_base_name'] + "-" + os.environ['project_name'] + '-edge'
     edge_instance_hostname = get_instance_hostname(notebook_config['tag_name'], edge_instance_name)
     edge_instance_private_ip = get_instance_ip_address(notebook_config['tag_name'], edge_instance_name).get('Private')
     if notebook_config['network_type'] == 'private':
diff --git a/infrastructure-provisioning/src/general/scripts/aws/rstudio_dataengine-service_create_configs.py b/infrastructure-provisioning/src/general/scripts/aws/rstudio_dataengine-service_create_configs.py
index 5534b73..f82c0f0 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/rstudio_dataengine-service_create_configs.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/rstudio_dataengine-service_create_configs.py
@@ -45,7 +45,7 @@
 parser.add_argument('--hadoop_version', type=str, default='')
 parser.add_argument('--region', type=str, default='')
 parser.add_argument('--excluded_lines', type=str, default='')
-parser.add_argument('--user_name', type=str, default='')
+parser.add_argument('--project_name', type=str, default='')
 parser.add_argument('--os_user', type=str, default='')
 args = parser.parse_args()
 
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 93f8bfc..4393b21 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
@@ -37,7 +37,7 @@
 parser.add_argument('--notebook_ip', type=str, default='')
 parser.add_argument('--scala_version', type=str, default='')
 parser.add_argument('--emr_excluded_spark_properties', 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='')
@@ -72,4 +72,4 @@
     sudo("/usr/bin/python /usr/local/bin/rstudio_dataengine-service_create_configs.py --bucket " + args.bucket +
          " --cluster_name " + args.cluster_name + " --emr_version " + args.emr_version + " --spark_version " +
          spark_version + " --hadoop_version " + hadoop_version + " --region " + args.region + " --excluded_lines '"
-         + args.emr_excluded_spark_properties + "' --user_name " + args.edge_user_name + " --os_user " + args.os_user)
+         + args.emr_excluded_spark_properties + "' --project_name " + args.project_name + " --os_user " + args.os_user)
diff --git a/infrastructure-provisioning/src/general/scripts/aws/ssn_configure.py b/infrastructure-provisioning/src/general/scripts/aws/ssn_configure.py
index b87e347..87ce81c 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/ssn_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/ssn_configure.py
@@ -262,6 +262,7 @@
         print('[CONFIGURING DOCKER AT SSN INSTANCE]')
         additional_config = [{"name": "base", "tag": "latest"},
                              {"name": "edge", "tag": "latest"},
+                             {"name": "project", "tag": "latest"},
                              {"name": "jupyter", "tag": "latest"},
                              {"name": "rstudio", "tag": "latest"},
                              {"name": "zeppelin", "tag": "latest"},
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 96b4cc3..420ba9e 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/tensor-rstudio_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/tensor-rstudio_configure.py
@@ -38,7 +38,7 @@
 
 if __name__ == "__main__":
     instance_class = 'notebook'
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -53,31 +53,31 @@
     notebook_config['service_base_name'] = os.environ['conf_service_base_name']
     notebook_config['instance_type'] = os.environ['aws_notebook_instance_type']
     notebook_config['key_name'] = os.environ['conf_key_name']
-    notebook_config['user_keyname'] = os.environ['edge_user_name']
+    notebook_config['user_keyname'] = os.environ['project_name']
     notebook_config['network_type'] = os.environ['conf_network_type']
     notebook_config['instance_name'] = '{}-{}-nb-{}-{}'.format(notebook_config['service_base_name'],
-                                                               os.environ['edge_user_name'],
+                                                               os.environ['project_name'],
                                                                notebook_config['exploratory_name'], args.uuid)
     notebook_config['expected_image_name'] = '{}-{}-notebook-image'.format(notebook_config['service_base_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'].lower().replace('-', '_'), os.environ['edge_user_name'])
+        .format(notebook_config['service_base_name'].lower().replace('-', '_'), os.environ['project_name'])
     notebook_config['security_group_name'] = '{}-{}-nb-SG'.format(notebook_config['service_base_name'],
-                                                                  os.environ['edge_user_name'])
+                                                                  os.environ['project_name'])
     notebook_config['tag_name'] = '{}-Tag'.format(notebook_config['service_base_name'])
     notebook_config['dlab_ssh_user'] = os.environ['conf_os_user']
     notebook_config['shared_image_enabled'] = os.environ['conf_shared_image_enabled']
     notebook_config['ip_address'] = get_instance_ip_address(notebook_config['tag_name'],
                                                             notebook_config['instance_name']).get('Private')
     tag = {"Key": notebook_config['tag_name'],
-           "Value": "{}-{}-subnet".format(notebook_config['service_base_name'], os.environ['edge_user_name'])}
+           "Value": "{}-{}-subnet".format(notebook_config['service_base_name'], os.environ['project_name'])}
     notebook_config['subnet_cidr'] = get_subnet_by_tag(tag)
     notebook_config['rstudio_pass'] = id_generator()
 
     # generating variables regarding EDGE proxy on Notebook instance
     instance_hostname = get_instance_hostname(notebook_config['tag_name'], notebook_config['instance_name'])
-    edge_instance_name = os.environ['conf_service_base_name'] + "-" + os.environ['edge_user_name'] + '-edge'
+    edge_instance_name = os.environ['conf_service_base_name'] + "-" + os.environ['project_name'] + '-edge'
     edge_instance_hostname = get_instance_hostname(notebook_config['tag_name'], edge_instance_name)
     edge_instance_private_ip = get_instance_ip_address(notebook_config['tag_name'], edge_instance_name).get('Private')
     if notebook_config['network_type'] == 'private':
diff --git a/infrastructure-provisioning/src/general/scripts/aws/tensor_configure.py b/infrastructure-provisioning/src/general/scripts/aws/tensor_configure.py
index 1230ce1..0f68666 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/tensor_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/tensor_configure.py
@@ -38,7 +38,7 @@
 
 if __name__ == "__main__":
     instance_class = 'notebook'
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -53,29 +53,29 @@
     notebook_config['service_base_name'] = os.environ['conf_service_base_name']
     notebook_config['instance_type'] = os.environ['aws_notebook_instance_type']
     notebook_config['key_name'] = os.environ['conf_key_name']
-    notebook_config['user_keyname'] = os.environ['edge_user_name']
+    notebook_config['user_keyname'] = os.environ['project_name']
     notebook_config['network_type'] = os.environ['conf_network_type']
     notebook_config['instance_name'] = '{}-{}-nb-{}-{}'.format(notebook_config['service_base_name'],
-                                                               os.environ['edge_user_name'],
+                                                               os.environ['project_name'],
                                                                notebook_config['exploratory_name'], args.uuid)
     notebook_config['expected_image_name'] = '{}-{}-notebook-image'.format(notebook_config['service_base_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'].lower().replace('-', '_'), os.environ['edge_user_name'])
+        .format(notebook_config['service_base_name'].lower().replace('-', '_'), os.environ['project_name'])
     notebook_config['security_group_name'] = '{}-{}-nb-SG'.format(notebook_config['service_base_name'],
-                                                                  os.environ['edge_user_name'])
+                                                                  os.environ['project_name'])
     notebook_config['tag_name'] = '{}-Tag'.format(notebook_config['service_base_name'])
     notebook_config['dlab_ssh_user'] = os.environ['conf_os_user']
     notebook_config['shared_image_enabled'] = os.environ['conf_shared_image_enabled']
     tag = {"Key": notebook_config['tag_name'],
-           "Value": "{}-{}-subnet".format(notebook_config['service_base_name'], os.environ['edge_user_name'])}
+           "Value": "{}-{}-subnet".format(notebook_config['service_base_name'], os.environ['project_name'])}
     notebook_config['subnet_cidr'] = get_subnet_by_tag(tag)
     notebook_config['ip_address'] = get_instance_ip_address(notebook_config['tag_name'], notebook_config['instance_name']).get('Private')
 
     # generating variables regarding EDGE proxy on Notebook instance
     instance_hostname = get_instance_hostname(notebook_config['tag_name'], notebook_config['instance_name'])
-    edge_instance_name = os.environ['conf_service_base_name'] + "-" + os.environ['edge_user_name'] + '-edge'
+    edge_instance_name = os.environ['conf_service_base_name'] + "-" + os.environ['project_name'] + '-edge'
     edge_instance_hostname = get_instance_hostname(notebook_config['tag_name'], edge_instance_name)
     edge_instance_private_ip = get_instance_ip_address(notebook_config['tag_name'], edge_instance_name).get('Private')
     if notebook_config['network_type'] == 'private':
diff --git a/infrastructure-provisioning/src/general/scripts/aws/zeppelin_configure.py b/infrastructure-provisioning/src/general/scripts/aws/zeppelin_configure.py
index b59cf37..60c71ad 100644
--- a/infrastructure-provisioning/src/general/scripts/aws/zeppelin_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/aws/zeppelin_configure.py
@@ -38,7 +38,7 @@
 
 if __name__ == "__main__":
     instance_class = 'notebook'
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -53,18 +53,18 @@
     notebook_config['service_base_name'] = os.environ['conf_service_base_name']
     notebook_config['instance_type'] = os.environ['aws_notebook_instance_type']
     notebook_config['key_name'] = os.environ['conf_key_name']
-    notebook_config['user_keyname'] = os.environ['edge_user_name']
+    notebook_config['user_keyname'] = os.environ['project_name']
     notebook_config['network_type'] = os.environ['conf_network_type']
     notebook_config['instance_name'] = '{}-{}-nb-{}-{}'.format(notebook_config['service_base_name'],
-                                                               os.environ['edge_user_name'],
+                                                               os.environ['project_name'],
                                                                notebook_config['exploratory_name'], args.uuid)
     notebook_config['expected_image_name'] = '{}-{}-notebook-image'.format(notebook_config['service_base_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'].lower().replace('-', '_'), os.environ['edge_user_name'])
+        .format(notebook_config['service_base_name'].lower().replace('-', '_'), os.environ['project_name'])
     notebook_config['security_group_name'] = '{}-{}-nb-SG'.format(notebook_config['service_base_name'],
-                                                                  os.environ['edge_user_name'])
+                                                                  os.environ['project_name'])
     notebook_config['tag_name'] = '{}-Tag'.format(notebook_config['service_base_name'])
     notebook_config['dlab_ssh_user'] = os.environ['conf_os_user']
     notebook_config['shared_image_enabled'] = os.environ['conf_shared_image_enabled']
@@ -80,7 +80,7 @@
 
     # generating variables regarding EDGE proxy on Notebook instance
     instance_hostname = get_instance_hostname(notebook_config['tag_name'], notebook_config['instance_name'])
-    edge_instance_name = os.environ['conf_service_base_name'] + "-" + os.environ['edge_user_name'] + '-edge'
+    edge_instance_name = os.environ['conf_service_base_name'] + "-" + os.environ['project_name'] + '-edge'
     edge_instance_hostname = get_instance_hostname(notebook_config['tag_name'], edge_instance_name)
     edge_instance_private_ip = get_instance_ip_address(notebook_config['tag_name'], edge_instance_name).get('Private')
     if notebook_config['network_type'] == 'private':
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 ea72a0a..bc452fc 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
@@ -46,7 +46,7 @@
 parser.add_argument('--hadoop_version', type=str, default='')
 parser.add_argument('--region', type=str, default='')
 parser.add_argument('--excluded_lines', type=str, default='')
-parser.add_argument('--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='')
@@ -100,8 +100,8 @@
         configuring_notebook(args.emr_version)
         if args.multiple_clusters == 'true':
             install_remote_livy(args)
-        installing_python(args.region, args.bucket, args.user_name, args.cluster_name, args.application,
+        installing_python(args.region, args.bucket, args.project_name, args.cluster_name, args.application,
                           args.pip_mirror, args.numpy_version)
         configure_zeppelin_emr_interpreter(args.emr_version, args.cluster_name, args.region, spark_dir, args.os_user,
-                                           yarn_dir, args.bucket, args.user_name, endpoint_url, args.multiple_clusters)
+                                           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 cbdff4d..7a04296 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
@@ -37,7 +37,7 @@
 parser.add_argument('--notebook_ip', type=str, default='')
 parser.add_argument('--scala_version', type=str, default='')
 parser.add_argument('--emr_excluded_spark_properties', 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='')
@@ -85,7 +85,7 @@
              "--hadoop_version {4} " \
              "--region {5} " \
              "--excluded_lines '{6}' " \
-             "--user_name {7} " \
+             "--project_name {7} " \
              "--os_user {8} " \
              "--edge_hostname {9} " \
              "--proxy_port {10} " \
@@ -103,7 +103,7 @@
                 hadoop_version,
                 args.region,
                 args.emr_excluded_spark_properties,
-                args.edge_user_name,
+                args.project_name,
                 args.os_user,
                 args.edge_hostname,
                 args.proxy_port,
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/project_prepare.py b/infrastructure-provisioning/src/general/scripts/gcp/project_prepare.py
new file mode 100644
index 0000000..eb60871
--- /dev/null
+++ b/infrastructure-provisioning/src/general/scripts/gcp/project_prepare.py
@@ -0,0 +1,467 @@
+#!/usr/bin/python
+
+# *****************************************************************************
+#
+# 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 json
+from dlab.fab import *
+from dlab.meta_lib import *
+import sys, time, os
+from dlab.actions_lib import *
+import traceback
+
+
+if __name__ == "__main__":
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/project/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    print('Generating infrastructure names and tags')
+    project_conf = dict()
+    project_conf['service_base_name'] = (os.environ['conf_service_base_name']).lower().replace('_', '-')
+    project_conf['key_name'] = os.environ['conf_key_name']
+    project_conf['user_keyname'] = os.environ['project_name']
+    project_conf['project_name'] = (os.environ['project_name']).lower().replace('_', '-')
+    try:
+        if os.environ['gcp_vpc_name'] == '':
+            raise KeyError
+        else:
+            project_conf['vpc_name'] = os.environ['gcp_vpc_name']
+    except KeyError:
+        project_conf['vpc_name'] = project_conf['service_base_name'] + '-ssn-vpc'
+    project_conf['vpc_cidr'] = os.environ['conf_vpc_cidr']
+    project_conf['private_subnet_name'] = '{0}-{1}-subnet'.format(project_conf['service_base_name'],
+                                                               project_conf['project_name'])
+    project_conf['subnet_name'] = os.environ['gcp_subnet_name']
+    project_conf['region'] = os.environ['gcp_region']
+    project_conf['zone'] = os.environ['gcp_zone']
+    project_conf['vpc_selflink'] = GCPMeta().get_vpc(project_conf['vpc_name'])['selfLink']
+    project_conf['private_subnet_prefix'] = os.environ['gcp_private_subnet_prefix']
+    project_conf['edge_service_account_name'] = '{}-{}-edge'.format(project_conf['service_base_name'],
+                                                                 project_conf['project_name'])
+    project_conf['edge_role_name'] = '{}-{}-edge'.format(project_conf['service_base_name'],
+                                                      project_conf['project_name'])
+    project_conf['ps_service_account_name'] = '{}-{}-ps'.format(project_conf['service_base_name'],
+                                                             project_conf['project_name'])
+    project_conf['ps_role_name'] = '{}-{}-ps'.format(project_conf['service_base_name'],
+                                                  project_conf['project_name'])
+    project_conf['ps_policy_path'] = '/root/files/ps_policy.json'
+    project_conf['ps_roles_path'] = '/root/files/ps_roles.json'
+    project_conf['instance_name'] = '{0}-{1}-edge'.format(project_conf['service_base_name'], edge_conf['project_name'])
+    project_conf['ssn_instance_name'] = '{}-ssn'.format(edge_conf['service_base_name'])
+    project_conf['bucket_name'] = '{0}-{1}-bucket'.format(project_conf['service_base_name'], edge_conf['project_name'])
+    project_conf['shared_bucket_name'] = '{}-shared-bucket'.format(project_conf['service_base_name'])
+    project_conf['instance_size'] = os.environ['gcp_edge_instance_size']
+    project_conf['ssh_key_path'] = '{0}{1}.pem'.format(os.environ['conf_key_dir'], os.environ['conf_key_name'])
+    project_conf['image_name'] = os.environ['gcp_{}_image_name'.format(os.environ['conf_os_family'])]
+    project_conf['static_address_name'] = '{0}-{1}-ip'.format(project_conf['service_base_name'], project_conf['project_name'])
+    project_conf['fw_edge_ingress_public'] = '{}-ingress-public'.format(project_conf['instance_name'])
+    project_conf['fw_edge_ingress_internal'] = '{}-ingress-internal'.format(project_conf['instance_name'])
+    project_conf['fw_edge_egress_public'] = '{}-egress-public'.format(project_conf['instance_name'])
+    project_conf['fw_edge_egress_internal'] = '{}-egress-internal'.format(project_conf['instance_name'])
+    project_conf['ps_firewall_target'] = '{0}-{1}-ps'.format(project_conf['service_base_name'],
+                                                          project_conf['project_name'])
+    project_conf['fw_common_name'] = '{}-{}-ps'.format(project_conf['service_base_name'], project_conf['project_name'])
+    project_conf['fw_ps_ingress'] = '{}-ingress'.format(project_conf['fw_common_name'])
+    project_conf['fw_ps_egress_private'] = '{}-egress-private'.format(project_conf['fw_common_name'])
+    project_conf['fw_ps_egress_public'] = '{}-egress-public'.format(project_conf['fw_common_name'])
+    project_conf['network_tag'] = project_conf['instance_name']
+    project_conf['instance_labels'] = {"name": project_conf['instance_name'],
+                                    "sbn": project_conf['service_base_name'],
+                                    "user": project_conf['project_name'],
+                                    "product": "dlab"}
+    project_conf['allowed_ip_cidr'] = os.environ['conf_allowed_ip_cidr']
+
+    # FUSE in case of absence of user's key
+    fname = "/root/keys/{}.pub".format(project_conf['user_keyname'])
+    if not os.path.isfile(fname):
+        print("USERs PUBLIC KEY DOES NOT EXIST in {}".format(fname))
+        sys.exit(1)
+
+    print("Will create exploratory environment with edge node as access point as following: ".format(json.dumps(
+        edge_conf, sort_keys=True, indent=4, separators=(',', ': '))))
+    logging.info(json.dumps(edge_conf))
+
+    try:
+        logging.info('[CREATE SUBNET]')
+        print('[CREATE SUBNET]')
+        params = "--subnet_name {} --region {} --vpc_selflink {} --prefix {} --vpc_cidr {}" \
+                 .format(edge_conf['private_subnet_name'], edge_conf['region'], edge_conf['vpc_selflink'],
+                         edge_conf['private_subnet_prefix'], edge_conf['vpc_cidr'])
+        try:
+            local("~/scripts/{}.py {}".format('common_create_subnet', params))
+            edge_conf['private_subnet_cidr'] = GCPMeta().get_subnet(edge_conf['private_subnet_name'],
+                                                                    edge_conf['region'])['ipCidrRange']
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        try:
+            GCPActions().remove_subnet(edge_conf['private_subnet_name'], edge_conf['region'])
+        except:
+            print("Subnet hasn't been created.")
+        append_result("Failed to create subnet.", str(err))
+        sys.exit(1)
+
+    print('NEW SUBNET CIDR CREATED: {}'.format(edge_conf['private_subnet_cidr']))
+
+    try:
+        logging.info('[CREATE SERVICE ACCOUNT AND ROLE FOR EDGE NODE]')
+        print('[CREATE SERVICE ACCOUNT AND ROLE FOR EDGE NODE]')
+        params = "--service_account_name {} --role_name {}".format(edge_conf['edge_service_account_name'],
+                                                                   edge_conf['edge_role_name'])
+
+        try:
+            local("~/scripts/{}.py {}".format('common_create_service_account', params))
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        try:
+            GCPActions().remove_service_account(edge_conf['edge_service_account_name'])
+            GCPActions().remove_role(edge_conf['edge_role_name'])
+        except:
+            print("Service account or role hasn't been created")
+        GCPActions().remove_subnet(edge_conf['private_subnet_name'], edge_conf['region'])
+        append_result("Failed to creating service account and role.", str(err))
+        sys.exit(1)
+
+    try:
+        logging.info('[CREATE SERVICE ACCOUNT AND ROLE FOR PRIVATE SUBNET]')
+        print('[CREATE SERVICE ACCOUNT AND ROLE FOR NOTEBOOK NODE]')
+        params = "--service_account_name {} --role_name {} --policy_path {} --roles_path {}".format(
+            edge_conf['ps_service_account_name'], edge_conf['ps_role_name'],
+            edge_conf['ps_policy_path'], edge_conf['ps_roles_path'])
+
+        try:
+            local("~/scripts/{}.py {}".format('common_create_service_account', params))
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        try:
+            GCPActions().remove_service_account(edge_conf['ps_service_account_name'])
+            GCPActions().remove_role(edge_conf['ps_role_name'])
+        except:
+            print("Service account or role hasn't been created")
+        GCPActions().remove_service_account(edge_conf['edge_service_account_name'])
+        GCPActions().remove_role(edge_conf['edge_role_name'])
+        GCPActions().remove_subnet(edge_conf['private_subnet_name'], edge_conf['region'])
+        append_result("Failed to creating service account and role.", str(err))
+        sys.exit(1)
+
+    try:
+        pre_defined_firewall = True
+        logging.info('[CREATE FIREWALL FOR EDGE NODE]')
+        print('[CREATE FIREWALL FOR EDGE NODE]')
+        firewall_rules = dict()
+        firewall_rules['ingress'] = []
+        firewall_rules['egress'] = []
+
+        ingress_rule = dict()
+        ingress_rule['name'] = edge_conf['fw_edge_ingress_public']
+        ingress_rule['targetTags'] = [edge_conf['network_tag']]
+        ingress_rule['sourceRanges'] = [edge_conf['allowed_ip_cidr']]
+        rules = [
+            {
+                'IPProtocol': 'tcp',
+                'ports': ['22', '80', '3128']
+            }
+        ]
+        ingress_rule['allowed'] = rules
+        ingress_rule['network'] = edge_conf['vpc_selflink']
+        ingress_rule['direction'] = 'INGRESS'
+        firewall_rules['ingress'].append(ingress_rule)
+
+        ingress_rule = dict()
+        ingress_rule['name'] = edge_conf['fw_edge_ingress_internal']
+        ingress_rule['targetTags'] = [edge_conf['network_tag']]
+        ingress_rule['sourceRanges'] = [edge_conf['private_subnet_cidr']]
+        rules = [
+            {
+                'IPProtocol': 'all'
+            }
+        ]
+        ingress_rule['allowed'] = rules
+        ingress_rule['network'] = edge_conf['vpc_selflink']
+        ingress_rule['direction'] = 'INGRESS'
+        firewall_rules['ingress'].append(ingress_rule)
+
+        egress_rule = dict()
+        egress_rule['name'] = edge_conf['fw_edge_egress_public']
+        egress_rule['targetTags'] = [edge_conf['network_tag']]
+        egress_rule['destinationRanges'] = [edge_conf['allowed_ip_cidr']]
+        rules = [
+            {
+                'IPProtocol': 'udp',
+                'ports': ['53', '123']
+            },
+            {
+                'IPProtocol': 'tcp',
+                'ports': ['80', '443']
+            }
+        ]
+        egress_rule['allowed'] = rules
+        egress_rule['network'] = edge_conf['vpc_selflink']
+        egress_rule['direction'] = 'EGRESS'
+        firewall_rules['egress'].append(egress_rule)
+
+        egress_rule = dict()
+        egress_rule['name'] = edge_conf['fw_edge_egress_internal']
+        egress_rule['targetTags'] = [edge_conf['network_tag']]
+        egress_rule['destinationRanges'] = [edge_conf['private_subnet_cidr']]
+        rules = [
+            {
+                'IPProtocol': 'tcp',
+                'ports': ['22', '389', '8888', '8080', '8787', '6006', '20888', '8042', '8088', '18080', '50070',
+                          '8085', '8081', '4040-4045']
+            }
+        ]
+        egress_rule['allowed'] = rules
+        egress_rule['network'] = edge_conf['vpc_selflink']
+        egress_rule['direction'] = 'EGRESS'
+        firewall_rules['egress'].append(egress_rule)
+
+        params = "--firewall '{}'".format(json.dumps(firewall_rules))
+        try:
+            local("~/scripts/{}.py {}".format('common_create_firewall', params))
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        GCPActions().remove_service_account(edge_conf['ps_service_account_name'])
+        GCPActions().remove_role(edge_conf['ps_role_name'])
+        GCPActions().remove_service_account(edge_conf['edge_service_account_name'])
+        GCPActions().remove_role(edge_conf['edge_role_name'])
+        append_result("Failed to create firewall for Edge node.", str(err))
+        GCPActions().remove_subnet(edge_conf['private_subnet_name'], edge_conf['region'])
+        sys.exit(1)
+
+    try:
+        logging.info('[CREATE FIREWALL FOR PRIVATE SUBNET]')
+        print('[CREATE FIREWALL FOR PRIVATE SUBNET]')
+        firewall_rules = dict()
+        firewall_rules['ingress'] = []
+        firewall_rules['egress'] = []
+
+        ingress_rule = dict()
+        ingress_rule['name'] = edge_conf['fw_ps_ingress']
+        ingress_rule['targetTags'] = [
+            edge_conf['ps_firewall_target']
+        ]
+        ingress_rule['sourceRanges'] = [edge_conf['private_subnet_cidr'],
+                                        GCPMeta().get_subnet(edge_conf['subnet_name'],
+                                                             edge_conf['region'])['ipCidrRange']
+                                        ]
+        rules = [
+            {
+                'IPProtocol': 'all'
+            }
+        ]
+        ingress_rule['allowed'] = rules
+        ingress_rule['network'] = edge_conf['vpc_selflink']
+        ingress_rule['direction'] = 'INGRESS'
+        firewall_rules['ingress'].append(ingress_rule)
+
+        egress_rule = dict()
+        egress_rule['name'] = edge_conf['fw_ps_egress_private']
+        egress_rule['targetTags'] = [
+            edge_conf['ps_firewall_target']
+        ]
+        egress_rule['destinationRanges'] = [edge_conf['private_subnet_cidr'],
+                                            GCPMeta().get_subnet(edge_conf['subnet_name'],
+                                                                 edge_conf['region'])['ipCidrRange']
+                                            ]
+        rules = [
+            {
+                'IPProtocol': 'all'
+            }
+        ]
+        egress_rule['allowed'] = rules
+        egress_rule['network'] = edge_conf['vpc_selflink']
+        egress_rule['direction'] = 'EGRESS'
+        firewall_rules['egress'].append(egress_rule)
+
+        egress_rule = dict()
+        egress_rule['name'] = edge_conf['fw_ps_egress_public']
+        egress_rule['targetTags'] = [
+            edge_conf['ps_firewall_target']
+        ]
+        egress_rule['destinationRanges'] = [edge_conf['allowed_ip_cidr']]
+        rules = [
+            {
+                'IPProtocol': 'tcp',
+                'ports': ['443']
+            }
+        ]
+        egress_rule['allowed'] = rules
+        egress_rule['network'] = edge_conf['vpc_selflink']
+        egress_rule['direction'] = 'EGRESS'
+        firewall_rules['egress'].append(egress_rule)
+
+        params = "--firewall '{}'".format(json.dumps(firewall_rules))
+        try:
+            local("~/scripts/{}.py {}".format('common_create_firewall', params))
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        append_result("Failed to create firewall for private subnet.", str(err))
+        GCPActions().remove_firewall(edge_conf['fw_edge_ingress_public'])
+        GCPActions().remove_firewall(edge_conf['fw_edge_ingress_internal'])
+        GCPActions().remove_firewall(edge_conf['fw_edge_egress_public'])
+        GCPActions().remove_firewall(edge_conf['fw_edge_egress_internal'])
+        GCPActions().remove_service_account(edge_conf['ps_service_account_name'])
+        GCPActions().remove_role(edge_conf['ps_role_name'])
+        GCPActions().remove_service_account(edge_conf['edge_service_account_name'])
+        GCPActions().remove_role(edge_conf['edge_role_name'])
+        GCPActions().remove_subnet(edge_conf['private_subnet_name'], edge_conf['region'])
+        sys.exit(1)
+
+    try:
+        logging.info('[CREATE BUCKETS]')
+        print('[CREATE BUCKETS]')
+        params = "--bucket_name {}".format(edge_conf['bucket_name'])
+
+        try:
+            local("~/scripts/{}.py {}".format('common_create_bucket', params))
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        append_result("Unable to create bucket.", str(err))
+        GCPActions().remove_firewall(edge_conf['fw_edge_ingress_public'])
+        GCPActions().remove_firewall(edge_conf['fw_edge_ingress_internal'])
+        GCPActions().remove_firewall(edge_conf['fw_edge_egress_public'])
+        GCPActions().remove_firewall(edge_conf['fw_edge_egress_internal'])
+        GCPActions().remove_firewall(edge_conf['fw_ps_ingress'])
+        GCPActions().remove_firewall(edge_conf['fw_ps_egress_private'])
+        GCPActions().remove_firewall(edge_conf['fw_ps_egress_public'])
+        GCPActions().remove_service_account(edge_conf['ps_service_account_name'])
+        GCPActions().remove_role(edge_conf['ps_role_name'])
+        GCPActions().remove_service_account(edge_conf['edge_service_account_name'])
+        GCPActions().remove_role(edge_conf['edge_role_name'])
+        GCPActions().remove_subnet(edge_conf['private_subnet_name'], edge_conf['region'])
+        sys.exit(1)
+
+    try:
+        logging.info('[SET PERMISSIONS FOR USER AND SHARED BUCKETS]')
+        print('[SET PERMISSIONS FOR USER AND SHARED BUCKETS]')
+        GCPActions().set_bucket_owner(edge_conf['bucket_name'], edge_conf['ps_service_account_name'])
+        GCPActions().set_bucket_owner(edge_conf['shared_bucket_name'], edge_conf['ps_service_account_name'])
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        append_result("Failed to set bucket permissions.", str(err))
+        GCPActions().remove_bucket(edge_conf['bucket_name'])
+        GCPActions().remove_firewall(edge_conf['fw_edge_ingress_public'])
+        GCPActions().remove_firewall(edge_conf['fw_edge_ingress_internal'])
+        GCPActions().remove_firewall(edge_conf['fw_edge_egress_public'])
+        GCPActions().remove_firewall(edge_conf['fw_edge_egress_internal'])
+        GCPActions().remove_firewall(edge_conf['fw_ps_ingress'])
+        GCPActions().remove_firewall(edge_conf['fw_ps_egress_private'])
+        GCPActions().remove_firewall(edge_conf['fw_ps_egress_public'])
+        GCPActions().remove_service_account(edge_conf['ps_service_account_name'])
+        GCPActions().remove_role(edge_conf['ps_role_name'])
+        GCPActions().remove_service_account(edge_conf['edge_service_account_name'])
+        GCPActions().remove_role(edge_conf['edge_role_name'])
+        GCPActions().remove_subnet(edge_conf['private_subnet_name'], edge_conf['region'])
+        sys.exit(1)
+
+    try:
+        logging.info('[CREATING STATIC IP ADDRESS]')
+        print('[CREATING STATIC IP ADDRESS]')
+        params = "--address_name {} --region {}".format(edge_conf['static_address_name'], edge_conf['region'])
+        try:
+            local("~/scripts/{}.py {}".format('edge_create_static_ip', params))
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        append_result("Failed to create static ip.", str(err))
+        try:
+            GCPActions().remove_static_address(edge_conf['static_address_name'], edge_conf['region'])
+        except:
+            print("Static IP address hasn't been created.")
+        GCPActions().remove_bucket(edge_conf['bucket_name'])
+        GCPActions().remove_firewall(edge_conf['fw_edge_ingress_public'])
+        GCPActions().remove_firewall(edge_conf['fw_edge_ingress_internal'])
+        GCPActions().remove_firewall(edge_conf['fw_edge_egress_public'])
+        GCPActions().remove_firewall(edge_conf['fw_edge_egress_internal'])
+        GCPActions().remove_firewall(edge_conf['fw_ps_ingress'])
+        GCPActions().remove_firewall(edge_conf['fw_ps_egress_private'])
+        GCPActions().remove_firewall(edge_conf['fw_ps_egress_public'])
+        GCPActions().remove_service_account(edge_conf['ps_service_account_name'])
+        GCPActions().remove_role(edge_conf['ps_role_name'])
+        GCPActions().remove_service_account(edge_conf['edge_service_account_name'])
+        GCPActions().remove_role(edge_conf['edge_role_name'])
+        GCPActions().remove_subnet(edge_conf['private_subnet_name'], edge_conf['region'])
+        sys.exit(1)
+
+    if os.environ['conf_os_family'] == 'debian':
+        initial_user = 'ubuntu'
+        sudo_group = 'sudo'
+    if os.environ['conf_os_family'] == 'redhat':
+        initial_user = 'ec2-user'
+        sudo_group = 'wheel'
+
+    try:
+        edge_conf['static_ip'] = \
+            GCPMeta().get_static_address(edge_conf['region'], edge_conf['static_address_name'])['address']
+        logging.info('[CREATE EDGE INSTANCE]')
+        print('[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 '{}'".\
+            format(edge_conf['instance_name'], edge_conf['region'], edge_conf['zone'], edge_conf['vpc_name'],
+                   edge_conf['subnet_name'], edge_conf['instance_size'], edge_conf['ssh_key_path'], initial_user,
+                   edge_conf['edge_service_account_name'], edge_conf['image_name'], 'edge', edge_conf['static_ip'],
+                   edge_conf['network_tag'], json.dumps(edge_conf['instance_labels']))
+        try:
+            local("~/scripts/{}.py {}".format('common_create_instance', params))
+        except:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        print('Error: {0}'.format(err))
+        append_result("Failed to create instance.", str(err))
+        GCPActions().remove_static_address(edge_conf['static_address_name'], edge_conf['region'])
+        GCPActions().remove_bucket(edge_conf['bucket_name'])
+        GCPActions().remove_firewall(edge_conf['fw_edge_ingress_public'])
+        GCPActions().remove_firewall(edge_conf['fw_edge_ingress_internal'])
+        GCPActions().remove_firewall(edge_conf['fw_edge_egress_public'])
+        GCPActions().remove_firewall(edge_conf['fw_edge_egress_internal'])
+        GCPActions().remove_firewall(edge_conf['fw_ps_ingress'])
+        GCPActions().remove_firewall(edge_conf['fw_ps_egress_private'])
+        GCPActions().remove_firewall(edge_conf['fw_ps_egress_public'])
+        GCPActions().remove_service_account(edge_conf['ps_service_account_name'])
+        GCPActions().remove_role(edge_conf['ps_role_name'])
+        GCPActions().remove_service_account(edge_conf['edge_service_account_name'])
+        GCPActions().remove_role(edge_conf['edge_role_name'])
+        GCPActions().remove_subnet(edge_conf['private_subnet_name'], edge_conf['region'])
+        sys.exit(1)
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/general/scripts/gcp/ssn_configure.py b/infrastructure-provisioning/src/general/scripts/gcp/ssn_configure.py
index fe8235f..a7aa2f9 100644
--- a/infrastructure-provisioning/src/general/scripts/gcp/ssn_configure.py
+++ b/infrastructure-provisioning/src/general/scripts/gcp/ssn_configure.py
@@ -215,7 +215,7 @@
         logging.info('[CONFIGURING DOCKER AT SSN INSTANCE]')
         print('[CONFIGURING DOCKER AT SSN INSTANCE]')
         additional_config = [{"name": "base", "tag": "latest"},
-                             {"name": "edge", "tag": "latest"},
+                             {"name": "project", "tag": "latest"},
                              {"name": "jupyter", "tag": "latest"},
                              {"name": "rstudio", "tag": "latest"},
                              {"name": "zeppelin", "tag": "latest"},
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 5cee0bc..622297a 100644
--- a/infrastructure-provisioning/src/general/scripts/os/common_clean_instance.py
+++ b/infrastructure-provisioning/src/general/scripts/os/common_clean_instance.py
@@ -119,7 +119,7 @@
     if os.environ['conf_cloud_provider'] == 'azure':
          de_master_name = '{}-{}-de-{}-{}-m'.format(
             os.environ['conf_service_base_name'],
-            os.environ['edge_user_name'].replace("_", "-"),
+            os.environ['project_name'].replace("_", "-"),
             os.environ['exploratory_name'].replace("_", "-"),
             os.environ['computational_name'].replace("_", "-"))
          de_ami_id = AzureMeta().get_instance_image(os.environ['azure_resource_group_name'],
@@ -128,7 +128,7 @@
     else:
         de_master_name = '{}-{}-de-{}-{}-m'.format(
             os.environ['conf_service_base_name'],
-            os.environ['edge_user_name'],
+            os.environ['project_name'],
             os.environ['exploratory_name'],
             os.environ['computational_name'])
         de_ami_id = get_ami_id_by_instance_name(de_master_name)
diff --git a/infrastructure-provisioning/src/general/scripts/os/dataengine_install_libs.py b/infrastructure-provisioning/src/general/scripts/os/dataengine_install_libs.py
index c7677ee..089e316 100644
--- a/infrastructure-provisioning/src/general/scripts/os/dataengine_install_libs.py
+++ b/infrastructure-provisioning/src/general/scripts/os/dataengine_install_libs.py
@@ -49,7 +49,7 @@
 
 if __name__ == "__main__":
     instance_class = 'notebook'
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
diff --git a/infrastructure-provisioning/src/general/scripts/os/dataengine_list_libs.py b/infrastructure-provisioning/src/general/scripts/os/dataengine_list_libs.py
index 6d17733..0cc5f6e 100644
--- a/infrastructure-provisioning/src/general/scripts/os/dataengine_list_libs.py
+++ b/infrastructure-provisioning/src/general/scripts/os/dataengine_list_libs.py
@@ -32,7 +32,7 @@
 
 if __name__ == "__main__":
     instance_class = 'notebook'
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
diff --git a/infrastructure-provisioning/src/general/scripts/os/dataengine_reconfigure_spark.py b/infrastructure-provisioning/src/general/scripts/os/dataengine_reconfigure_spark.py
index 67c30fa..006a313 100644
--- a/infrastructure-provisioning/src/general/scripts/os/dataengine_reconfigure_spark.py
+++ b/infrastructure-provisioning/src/general/scripts/os/dataengine_reconfigure_spark.py
@@ -49,7 +49,7 @@
 
 if __name__ == "__main__":
     instance_class = 'notebook'
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
diff --git a/infrastructure-provisioning/src/general/scripts/os/notebook_git_creds.py b/infrastructure-provisioning/src/general/scripts/os/notebook_git_creds.py
index 81719ba..23f889f 100644
--- a/infrastructure-provisioning/src/general/scripts/os/notebook_git_creds.py
+++ b/infrastructure-provisioning/src/general/scripts/os/notebook_git_creds.py
@@ -32,7 +32,7 @@
 
 if __name__ == "__main__":
     instance_class = 'notebook'
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
diff --git a/infrastructure-provisioning/src/general/scripts/os/notebook_inactivity_check.py b/infrastructure-provisioning/src/general/scripts/os/notebook_inactivity_check.py
index 85f3b8e..59074f8 100644
--- a/infrastructure-provisioning/src/general/scripts/os/notebook_inactivity_check.py
+++ b/infrastructure-provisioning/src/general/scripts/os/notebook_inactivity_check.py
@@ -30,8 +30,8 @@
 
 
 if __name__ == "__main__":
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'], os.environ['request_id'])
-    local_log_filepath = "/logs/edge/" + local_log_filename
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'], os.environ['request_id'])
+    local_log_filepath = "/logs/project/" + local_log_filename
     logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
                         level=logging.DEBUG,
                         filename=local_log_filepath)
diff --git a/infrastructure-provisioning/src/general/scripts/os/notebook_install_libs.py b/infrastructure-provisioning/src/general/scripts/os/notebook_install_libs.py
index 2b2559e..17abe27 100644
--- a/infrastructure-provisioning/src/general/scripts/os/notebook_install_libs.py
+++ b/infrastructure-provisioning/src/general/scripts/os/notebook_install_libs.py
@@ -33,7 +33,7 @@
 
 if __name__ == "__main__":
     instance_class = 'notebook'
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
diff --git a/infrastructure-provisioning/src/general/scripts/os/notebook_list_libs.py b/infrastructure-provisioning/src/general/scripts/os/notebook_list_libs.py
index 49387b3..839f3f9 100644
--- a/infrastructure-provisioning/src/general/scripts/os/notebook_list_libs.py
+++ b/infrastructure-provisioning/src/general/scripts/os/notebook_list_libs.py
@@ -32,7 +32,7 @@
 
 if __name__ == "__main__":
     instance_class = 'notebook'
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
diff --git a/infrastructure-provisioning/src/general/scripts/os/notebook_reconfigure_spark.py b/infrastructure-provisioning/src/general/scripts/os/notebook_reconfigure_spark.py
index f5f0116..849333c 100644
--- a/infrastructure-provisioning/src/general/scripts/os/notebook_reconfigure_spark.py
+++ b/infrastructure-provisioning/src/general/scripts/os/notebook_reconfigure_spark.py
@@ -33,7 +33,7 @@
 
 if __name__ == "__main__":
     instance_class = 'notebook'
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
diff --git a/infrastructure-provisioning/src/project/fabfile.py b/infrastructure-provisioning/src/project/fabfile.py
new file mode 100644
index 0000000..5949469
--- /dev/null
+++ b/infrastructure-provisioning/src/project/fabfile.py
@@ -0,0 +1,75 @@
+#!/usr/bin/python
+
+# *****************************************************************************
+#
+# 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 json
+from fabric.api import *
+import logging
+import sys
+import os
+from dlab.fab import *
+import traceback
+
+
+def run():
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'],
+                                            os.environ['request_id'])
+    local_log_filepath = "/logs/project/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        local("~/scripts/{}.py".format('project_prepare'))
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed preparing Project.", str(err))
+        sys.exit(1)
+
+#    try:
+#        local("~/scripts/{}.py".format('edge_prepare'))
+#    except Exception as err:
+#        traceback.print_exc()
+#        append_result("Failed preparing Edge node.", str(err))
+#        sys.exit(1)
+
+    try:
+        local("~/scripts/{}.py".format('edge_configure'))
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed configuring Edge node.", str(err))
+        sys.exit(1)
+
+# Main function for terminating EDGE node and exploratory environment if exists
+def terminate():
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['project_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/project/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+    try:
+        local("~/scripts/{}.py".format('project_terminate'))
+    except Exception as err:
+        traceback.print_exc()
+        append_result("Failed terminating Edge node.", str(err))
+        sys.exit(1)
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/project/scripts/configure_http_proxy.py b/infrastructure-provisioning/src/project/scripts/configure_http_proxy.py
new file mode 100644
index 0000000..bad50ad
--- /dev/null
+++ b/infrastructure-provisioning/src/project/scripts/configure_http_proxy.py
@@ -0,0 +1,52 @@
+#!/usr/bin/python
+
+# *****************************************************************************
+#
+# 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 fabric.api import *
+from fabric.contrib.files import exists
+from dlab.edge_lib import configure_http_proxy_server
+import argparse
+import json
+import sys
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--hostname', type=str, default='')
+parser.add_argument('--keyfile', type=str, default='')
+parser.add_argument('--user', type=str, default='')
+parser.add_argument('--additional_config', type=str, default='{"empty":"string"}')
+args = parser.parse_args()
+
+##############
+# Run script #
+##############
+if __name__ == "__main__":
+    print("Configure connections")
+    try:
+        env['connection_attempts'] = 100
+        env.key_filename = [args.keyfile]
+        env.host_string = '{}@{}'.format(args.user, args.hostname)
+        deeper_config = json.loads(args.additional_config)
+    except:
+        sys.exit(2)
+
+    print("Installing proxy for notebooks.")
+    configure_http_proxy_server(deeper_config)
diff --git a/infrastructure-provisioning/src/project/scripts/configure_nginx_reverse_proxy.py b/infrastructure-provisioning/src/project/scripts/configure_nginx_reverse_proxy.py
new file mode 100644
index 0000000..2d564f7
--- /dev/null
+++ b/infrastructure-provisioning/src/project/scripts/configure_nginx_reverse_proxy.py
@@ -0,0 +1,63 @@
+#!/usr/bin/python
+
+# *****************************************************************************
+#
+# 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
+from fabric.api import *
+import argparse
+import sys
+import os
+from dlab.edge_lib import install_nginx_ldap
+
+parser = argparse.ArgumentParser()
+parser.add_argument('--hostname', type=str, default='')
+parser.add_argument('--keyfile', type=str, default='')
+parser.add_argument('--user', type=str, default='')
+args = parser.parse_args()
+
+if __name__ == "__main__":
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'],
+                                               os.environ['project_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/edge/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    print("Configure connections")
+    try:
+        env['connection_attempts'] = 100
+        env.key_filename = [args.keyfile]
+        env.host_string = '{}@{}'.format(args.user, args.hostname)
+    except Exception as err:
+        print("Failed establish connection. Excpeption: " + str(err))
+        sys.exit(1)
+
+    try:
+        install_nginx_ldap(args.hostname, os.environ['reverse_proxy_nginx_version'],
+                           os.environ['ldap_hostname'], os.environ['ldap_dn'],
+                           os.environ['ldap_ou'], os.environ['ldap_service_password'],
+                           os.environ['ldap_service_username'])
+    except Exception as err:
+        print("Failed install nginx reverse proxy: " + str(err))
+        sys.exit(1)
+
diff --git a/infrastructure-provisioning/src/project/scripts/reupload_ssh_key.py b/infrastructure-provisioning/src/project/scripts/reupload_ssh_key.py
new file mode 100644
index 0000000..b853af5
--- /dev/null
+++ b/infrastructure-provisioning/src/project/scripts/reupload_ssh_key.py
@@ -0,0 +1,71 @@
+#!/usr/bin/python
+
+# *****************************************************************************
+#
+# 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 os
+import sys
+import logging
+import traceback
+from dlab.fab import *
+from dlab.meta_lib import *
+from dlab.actions_lib import *
+from fabric.api import *
+import multiprocessing
+
+if __name__ == "__main__":
+    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+                                               os.environ['request_id'])
+    local_log_filepath = "/logs/edge/" + local_log_filename
+    logging.basicConfig(format='%(levelname)-8s [%(asctime)s]  %(message)s',
+                        level=logging.DEBUG,
+                        filename=local_log_filepath)
+
+    try:
+        if os.environ['conf_cloud_provider'] == 'aws':
+            create_aws_config_files()
+        logging.info('[REUPLOADING USER SSH KEY]')
+        print('[REUPLOADING USER SSH KEY]')
+        reupload_config = dict()
+        reupload_config['os_user'] = os.environ['conf_os_user']
+        reupload_config['edge_user_name'] = os.environ['edge_user_name']
+        reupload_config['keyfile'] = '{}{}.pem'.format(os.environ['conf_key_dir'], os.environ['conf_key_name'])
+        reupload_config['resource_id'] = os.environ['resource_id']
+        reupload_config['additional_config'] = {"user_keyname": reupload_config['edge_user_name'],
+                                                "user_keydir": os.environ['conf_key_dir']}
+        print(reupload_config)
+        try:
+            params = "--conf_resource {} --instance_id {} --os_user '{}'" \
+                     " --keyfile '{}' --additional_config '{}'".format(
+                os.environ['conf_resource'], reupload_config['resource_id'],
+                reupload_config['os_user'],  reupload_config['keyfile'],
+                json.dumps(reupload_config['additional_config']))
+            local("~/scripts/{}.py {}".format('common_reupload_key', params))
+        except Exception as err:
+            traceback.print_exc()
+            raise Exception
+    except Exception as err:
+        append_result("Failed to reupload user ssh key.", str(err))
+        sys.exit(1)
+
+    with open("/root/result.json", 'w') as result:
+        res = {"Action": "Reupload user ssh key"}
+        result.write(json.dumps(res))
\ 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
new file mode 100644
index 0000000..3c46029
--- /dev/null
+++ b/infrastructure-provisioning/src/project/templates/conf.d/proxy.conf
@@ -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.
+#
+# ******************************************************************************
+server {
+    listen 80;
+    server_name EDGE_IP;
+	auth_ldap "Forbidden";
+    auth_ldap_servers ldap1;
+
+    include locations/*.conf;
+}
diff --git a/infrastructure-provisioning/src/edge/templates/locations/dataengine-service.conf b/infrastructure-provisioning/src/project/templates/locations/dataengine-service.conf
similarity index 100%
rename from infrastructure-provisioning/src/edge/templates/locations/dataengine-service.conf
rename to infrastructure-provisioning/src/project/templates/locations/dataengine-service.conf
diff --git a/infrastructure-provisioning/src/project/templates/locations/jupyter.conf b/infrastructure-provisioning/src/project/templates/locations/jupyter.conf
new file mode 100644
index 0000000..56f98ed
--- /dev/null
+++ b/infrastructure-provisioning/src/project/templates/locations/jupyter.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/locations/rstudio.conf b/infrastructure-provisioning/src/project/templates/locations/rstudio.conf
new file mode 100644
index 0000000..4c63f97
--- /dev/null
+++ b/infrastructure-provisioning/src/project/templates/locations/rstudio.conf
@@ -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.
+#
+# ******************************************************************************
+location /{{ NAME }}/ {
+      rewrite ^/{{ NAME }}/(.*)$ /$1 break;
+      proxy_pass http://{{ IP }}:8787;
+      proxy_redirect http://{{ IP }}:8787/ $scheme://$host/{{ NAME }}/;
+      proxy_http_version 1.1;
+      proxy_set_header Upgrade $http_upgrade;
+      proxy_set_header Connection "upgrade";
+      proxy_read_timeout 20d;
+}
+
diff --git a/infrastructure-provisioning/src/project/templates/locations/spark.conf b/infrastructure-provisioning/src/project/templates/locations/spark.conf
new file mode 100644
index 0000000..554de78
--- /dev/null
+++ b/infrastructure-provisioning/src/project/templates/locations/spark.conf
@@ -0,0 +1,123 @@
+# *****************************************************************************
+#
+# 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 /{{ CLUSTER_NAME }}/ {
+    rewrite ^/{{ CLUSTER_NAME }}/(.*)$ /$1 break;
+    proxy_pass http://{{ MASTER_IP }}:8080;
+    proxy_redirect http://{{ MASTER_IP }}:8080/ $scheme://$host/{{ CLUSTER_NAME }}/;
+    proxy_set_header Accept-Encoding "";
+    proxy_http_version 1.1;
+    proxy_set_header Upgrade $http_upgrade;
+    proxy_set_header Connection "upgrade";
+    sub_filter_types *;
+    sub_filter_once off;
+    sub_filter '/static/' '/{{ CLUSTER_NAME }}/static/';
+    sub_filter '/app/' '/{{ CLUSTER_NAME }}/app/';
+    sub_filter '<a href="/"' '<a href="/{{ CLUSTER_NAME }}/"';
+    sub_filter '//{{ MASTER_DNS }}:7077' '//$host/{{ CLUSTER_NAME }}-client-master';
+    sub_filter '//{{ MASTER_DNS }}:6066' '//$host/{{ CLUSTER_NAME }}-cluster-master';
+    sub_filter '//{{ NOTEBOOK_IP }}:4040' '//$host/{{ CLUSTER_NAME }}-driver';
+    sub_filter '//{{ MASTER_IP }}:8081' '//$host/{{ CLUSTER_NAME }}-master-datanode';
+    {% for item in slaves %}
+    sub_filter '//{{ item.ip }}:8081' '//$host/{{ CLUSTER_NAME }}-{{ item.name }}';
+    {% endfor %}
+}
+
+location /{{ CLUSTER_NAME }}-client-master/ {
+    rewrite ^/{{ CLUSTER_NAME }}-client-master/(.*)$ /$1 break;
+    proxy_pass http://{{ MASTER_IP }}:7077;
+    proxy_redirect http://{{ MASTER_IP }}:7077/ $scheme://$host/{{ CLUSTER_NAME }}-client-master/;
+    proxy_set_header Accept-Encoding "";
+    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";
+    sub_filter '<a href="/"' '<a href="/{{ CLUSTER_NAME }}/"';
+}
+
+location /{{ CLUSTER_NAME }}-cluster-master/ {
+    rewrite ^/{{ CLUSTER_NAME }}-cluster-master/(.*)$ /$1 break;
+    proxy_pass http://{{ MASTER_IP }}:6066;
+    proxy_redirect http://{{ MASTER_IP }}:6066/ $scheme://$host/{{ CLUSTER_NAME }}-cluster-master/;
+    proxy_set_header Accept-Encoding "";
+    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";
+}
+
+location /{{ CLUSTER_NAME }}-driver/ {
+    rewrite ^/{{ CLUSTER_NAME }}-driver/(.*)$ /$1 break;
+    proxy_pass http://{{ NOTEBOOK_IP }}:4040;
+    proxy_redirect http://{{ NOTEBOOK_IP }}:4040/ $scheme://$host/{{ CLUSTER_NAME }}-driver/;
+    proxy_set_header Accept-Encoding "";
+    proxy_http_version 1.1;
+    proxy_set_header Upgrade $http_upgrade;
+    proxy_set_header Connection "upgrade";
+    sub_filter_types *;
+    sub_filter_once off;
+    sub_filter '<a href="/"' '<a href="/{{ CLUSTER_NAME }}/"';
+    sub_filter '/jobs/' '/{{ CLUSTER_NAME }}-driver/jobs/';
+    sub_filter '/static/' '/{{ CLUSTER_NAME }}-driver/static/';
+    sub_filter '/stages/' '/{{ CLUSTER_NAME }}-driver/stages/';
+    sub_filter '/storage/' '/{{ CLUSTER_NAME }}-driver/storage/';
+    sub_filter '/environment/' '/{{ CLUSTER_NAME }}-driver/environment/';
+    sub_filter '/executors/' '/{{ CLUSTER_NAME }}-driver/executors/';
+    sub_filter '/SQL/' '/{{ CLUSTER_NAME }}-driver/SQL/';
+}
+
+location /{{ CLUSTER_NAME }}-master-datanode/ {
+    rewrite ^/{{ CLUSTER_NAME }}-master-datanode/(.*)$ /$1 break;
+    proxy_pass http://{{ MASTER_IP }}:8081;
+    proxy_redirect http://{{ MASTER_IP }}:8081/ $scheme://$host/{{ CLUSTER_NAME }}-master-datanode/;
+    proxy_set_header Accept-Encoding "";
+    proxy_http_version 1.1;
+    proxy_set_header Upgrade $http_upgrade;
+    proxy_set_header Connection "upgrade";
+    sub_filter_types *;
+    sub_filter_once off;
+    sub_filter '/static/' '/{{ CLUSTER_NAME }}-master-datanode/static/';
+    sub_filter '<a href="/"' '<a href="/{{ CLUSTER_NAME }}/"';
+    sub_filter '//{{ MASTER_DNS }}:7077' '//$host/{{ CLUSTER_NAME }}-client-master';
+    sub_filter '//{{ MASTER_DNS }}:8080' '//$host/{{ CLUSTER_NAME }}';
+}
+
+{% for item in slaves %}
+location /{{ CLUSTER_NAME }}-{{ item.name }}/ {
+    rewrite ^/{{ CLUSTER_NAME }}-{{ item.name }}/(.*)$ /$1 break;
+    proxy_pass http://{{ item.ip }}:8081;
+    proxy_redirect http://{{ item.ip }}:8081/ $scheme://$host/{{ CLUSTER_NAME }}-{{ item.name }}/;
+    proxy_set_header Accept-Encoding "";
+    proxy_http_version 1.1;
+    proxy_set_header Upgrade $http_upgrade;
+    proxy_set_header Connection "upgrade";
+    sub_filter_types *;
+    sub_filter_once off;
+    sub_filter '/static/' '/{{ CLUSTER_NAME }}-{{ item.name }}/static/';
+    sub_filter '<a href="/"' '<a href="/{{ CLUSTER_NAME }}/"';
+    sub_filter '//{{ MASTER_DNS }}:7077' '//$host/{{ CLUSTER_NAME }}-client-master';
+    sub_filter '//{{ MASTER_DNS }}:8080' '//$host/{{ CLUSTER_NAME }}';
+}
+
+{% endfor %}
diff --git a/infrastructure-provisioning/src/project/templates/locations/tensor.conf b/infrastructure-provisioning/src/project/templates/locations/tensor.conf
new file mode 100644
index 0000000..f6df456
--- /dev/null
+++ b/infrastructure-provisioning/src/project/templates/locations/tensor.conf
@@ -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.
+#
+# ******************************************************************************
+location /{{ NAME }}-tensor/ {
+    rewrite ^/{{ NAME }}-tensor/(.*)$ /$1 break;
+    proxy_pass http://{{ IP }}:6006;
+    proxy_redirect http://{{ IP }}:6006/ $scheme://$host/{{ NAME }}-tensor/;
+    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/locations/ungit.conf b/infrastructure-provisioning/src/project/templates/locations/ungit.conf
new file mode 100644
index 0000000..5b7b3ed
--- /dev/null
+++ b/infrastructure-provisioning/src/project/templates/locations/ungit.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 }}-ungit/.* {
+    proxy_pass http://{{ IP }}:8085;
+    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";
+}
\ No newline at end of file
diff --git a/infrastructure-provisioning/src/project/templates/locations/zeppelin.conf b/infrastructure-provisioning/src/project/templates/locations/zeppelin.conf
new file mode 100644
index 0000000..231045e
--- /dev/null
+++ b/infrastructure-provisioning/src/project/templates/locations/zeppelin.conf
@@ -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.
+#
+# ******************************************************************************
+location /{{ NAME }}/ {
+    rewrite ^/{{ NAME }}/(.*)$ /$1 break;
+    proxy_pass http://{{ IP }}:8080;
+    proxy_redirect http://{{ IP }}:8080/ $scheme://$host/{{ NAME }}/;
+    proxy_http_version 1.1;
+    proxy_set_header Upgrade $http_upgrade;
+    proxy_set_header Connection "upgrade";
+}
diff --git a/infrastructure-provisioning/src/project/templates/nginx.conf b/infrastructure-provisioning/src/project/templates/nginx.conf
new file mode 100644
index 0000000..f3f4958
--- /dev/null
+++ b/infrastructure-provisioning/src/project/templates/nginx.conf
@@ -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.
+#
+# ******************************************************************************
+user nginx;
+worker_processes auto;
+error_log /var/log/nginx/error.log;
+pid /run/nginx.pid;
+
+include /usr/share/nginx/modules/*.conf;
+
+events {
+    worker_connections 1024;
+}
+
+http {
+    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
+                      '$status $body_bytes_sent "$http_referer" '
+                      '"$http_user_agent" "$http_x_forwarded_for"';
+
+    access_log  /var/log/nginx/access.log  main;
+
+    sendfile            on;
+    tcp_nopush          on;
+    tcp_nodelay         on;
+    keepalive_timeout   100;
+    types_hash_max_size 2048;
+    proxy_read_timeout 86400s;
+    proxy_send_timeout 86400s;
+    client_max_body_size 50M;
+
+    include             /etc/nginx/mime.types;
+    default_type        application/octet-stream;
+
+    auth_ldap_cache_enabled on;
+    auth_ldap_cache_expiration_time 10000;
+    auth_ldap_cache_size 1000;
+
+    ldap_server ldap1 {
+        url ldap://LDAP_IP:389/LDAP_DN?uid,mail?sub?(&(objectClass=posixAccount));
+        binddn "LDAP_SERVICE_USERNAME,LDAP_DN";
+        binddn_passwd "LDAP_SERVICE_PASSWORD";
+        require valid_user;
+        request_timeout 30s;
+    }
+
+    include /etc/nginx/conf.d/*.conf;
+}
diff --git a/infrastructure-provisioning/src/project/templates/nginx_debian b/infrastructure-provisioning/src/project/templates/nginx_debian
new file mode 100644
index 0000000..997bec9
--- /dev/null
+++ b/infrastructure-provisioning/src/project/templates/nginx_debian
@@ -0,0 +1,216 @@
+#!/bin/sh
+# *****************************************************************************
+#
+# 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.
+#
+# ******************************************************************************
+
+### BEGIN INIT INFO
+# Provides:       nginx
+# Required-Start:    $local_fs $remote_fs $network $syslog $named
+# Required-Stop:     $local_fs $remote_fs $network $syslog $named
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Short-Description: starts the nginx web server
+# Description:       starts nginx using start-stop-daemon
+### END INIT INFO
+
+PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
+DAEMON=/usr/sbin/nginx
+NAME=nginx
+DESC=nginx
+
+# Include nginx defaults if available
+if [ -r /etc/default/nginx ]; then
+        . /etc/default/nginx
+fi
+
+STOP_SCHEDULE="${STOP_SCHEDULE:-QUIT/5/TERM/5/KILL/5}"
+
+test -x $DAEMON || exit 0
+
+. /lib/init/vars.sh
+. /lib/lsb/init-functions
+
+# Try to extract nginx pidfile
+PID=$(cat /etc/nginx/nginx.conf | grep -Ev '^\s*#' | awk 'BEGIN { RS="[;{}]" } { if ($1 == "pid") print $2 }' | head -n1)
+if [ -z "$PID" ]; then
+        PID=/run/nginx.pid
+fi
+
+if [ -n "$ULIMIT" ]; then
+        # Set ulimit if it is set in /etc/default/nginx
+        ulimit $ULIMIT
+fi
+
+start_nginx() {
+        # Start the daemon/service
+        #
+        # Returns:
+        #   0 if daemon has been started
+        #   1 if daemon was already running
+        #   2 if daemon could not be started
+        start-stop-daemon --start --quiet --pidfile $PID --exec $DAEMON --test > /dev/null \
+                || return 1
+        start-stop-daemon --start --quiet --pidfile $PID --exec $DAEMON -- \
+                $DAEMON_OPTS 2>/dev/null \
+                || return 2
+}
+
+test_config() {
+        # Test the nginx configuration
+        $DAEMON -t $DAEMON_OPTS >/dev/null 2>&1
+}
+
+stop_nginx() {
+        # Stops the daemon/service
+        #
+        # Return
+        #   0 if daemon has been stopped
+        #   1 if daemon was already stopped
+        #   2 if daemon could not be stopped
+        #   other if a failure occurred
+        start-stop-daemon --stop --quiet --retry=$STOP_SCHEDULE --pidfile $PID --name $NAME
+        RETVAL="$?"
+        sleep 1
+        return "$RETVAL"
+}
+
+reload_nginx() {
+        # Function that sends a SIGHUP to the daemon/service
+        start-stop-daemon --stop --signal HUP --quiet --pidfile $PID --name $NAME
+        return 0
+}
+
+rotate_logs() {
+        # Rotate log files
+        start-stop-daemon --stop --signal USR1 --quiet --pidfile $PID --name $NAME
+        return 0
+}
+
+upgrade_nginx() {
+        # Online upgrade nginx executable
+        # http://nginx.org/en/docs/control.html
+        #
+        # Return
+        #   0 if nginx has been successfully upgraded
+        #   1 if nginx is not running
+        #   2 if the pid files were not created on time
+        #   3 if the old master could not be killed
+        if start-stop-daemon --stop --signal USR2 --quiet --pidfile $PID --name $NAME; then
+                # Wait for both old and new master to write their pid file
+                while [ ! -s "${PID}.oldbin" ] || [ ! -s "${PID}" ]; do
+                        cnt=`expr $cnt + 1`
+                        if [ $cnt -gt 10 ]; then
+                                return 2
+                        fi
+                        sleep 1
+                done
+                # Everything is ready, gracefully stop the old master
+                if start-stop-daemon --stop --signal QUIT --quiet --pidfile "${PID}.oldbin" --name $NAME; then
+                        return 0
+                else
+                        return 3
+                fi
+        else
+                return 1
+        fi
+}
+
+case "$1" in
+        start)
+                log_daemon_msg "Starting $DESC" "$NAME"
+                start_nginx
+                case "$?" in
+                        0|1) log_end_msg 0 ;;
+                        2)   log_end_msg 1 ;;
+                esac
+                ;;
+        stop)
+                log_daemon_msg "Stopping $DESC" "$NAME"
+                stop_nginx
+                case "$?" in
+                        0|1) log_end_msg 0 ;;
+                        2)   log_end_msg 1 ;;
+                esac
+                ;;
+        restart)
+                log_daemon_msg "Restarting $DESC" "$NAME"
+
+                # Check configuration before stopping nginx
+                if ! test_config; then
+                        log_end_msg 1 # Configuration error
+                        exit $?
+                fi
+
+                stop_nginx
+                case "$?" in
+                        0|1)
+                                start_nginx
+                                case "$?" in
+                                        0) log_end_msg 0 ;;
+                                        1) log_end_msg 1 ;; # Old process is still running
+                                        *) log_end_msg 1 ;; # Failed to start
+                                esac
+                                ;;
+                        *)
+                                # Failed to stop
+                                log_end_msg 1
+                                ;;
+                esac
+                ;;
+        reload|force-reload)
+                log_daemon_msg "Reloading $DESC configuration" "$NAME"
+
+                # Check configuration before stopping nginx
+                #
+                # This is not entirely correct since the on-disk nginx binary
+                # may differ from the in-memory one, but that's not common.
+                # We prefer to check the configuration and return an error
+                # to the administrator.
+                if ! test_config; then
+                        log_end_msg 1 # Configuration error
+                        exit $?
+                fi
+
+                reload_nginx
+                log_end_msg $?
+                ;;
+        configtest|testconfig)
+                log_daemon_msg "Testing $DESC configuration"
+                test_config
+                log_end_msg $?
+                ;;
+        status)
+                status_of_proc -p $PID "$DAEMON" "$NAME" && exit 0 || exit $?
+                ;;
+        upgrade)
+                log_daemon_msg "Upgrading binary" "$NAME"
+                upgrade_nginx
+                log_end_msg $?
+                ;;
+        rotate)
+                log_daemon_msg "Re-opening $DESC log files" "$NAME"
+                rotate_logs
+                log_end_msg $?
+                ;;
+        *)
+                echo "Usage: $NAME {start|stop|restart|reload|force-reload|status|configtest|rotate|upgrade}" >&2
+                exit 3
+                ;;
+esac
diff --git a/infrastructure-provisioning/src/project/templates/nginx_redhat b/infrastructure-provisioning/src/project/templates/nginx_redhat
new file mode 100644
index 0000000..8f2c4c9
--- /dev/null
+++ b/infrastructure-provisioning/src/project/templates/nginx_redhat
@@ -0,0 +1,128 @@
+#!/bin/sh
+# *****************************************************************************
+#
+# 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.
+#
+# ******************************************************************************
+
+#
+# nginx - this script starts and stops the nginx daemon
+#
+# chkconfig:   - 85 15
+# description:  Nginx is an HTTP(S) server, HTTP(S) reverse \
+#               proxy and IMAP/POP3 proxy server
+# processname: nginx
+# config:      /etc/nginx/nginx.conf
+# pidfile:     /var/run/nginx.pid
+# user:        nginx
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+# Source networking configuration.
+. /etc/sysconfig/network
+
+# Check that networking is up.
+[ "$NETWORKING" = "no" ] && exit 0
+
+nginx="/usr/sbin/nginx"
+prog=$(basename $nginx)
+
+NGINX_CONF_FILE="/etc/nginx/nginx.conf"
+
+lockfile=/var/run/nginx.lock
+
+start() {
+    [ -x $nginx ] || exit 5
+    [ -f $NGINX_CONF_FILE ] || exit 6
+    echo -n $"Starting $prog: "
+    daemon $nginx -c $NGINX_CONF_FILE
+    retval=$?
+    echo
+    [ $retval -eq 0 ] && touch $lockfile
+    return $retval
+}
+
+stop() {
+    echo -n $"Stopping $prog: "
+    killproc $prog -QUIT
+    retval=$?
+    echo
+    [ $retval -eq 0 ] && rm -f $lockfile
+    return $retval
+}
+
+restart() {
+    configtest || return $?
+    stop
+    start
+}
+
+reload() {
+    configtest || return $?
+    echo -n $"Reloading $prog: "
+    killproc $nginx -HUP
+    RETVAL=$?
+    echo
+}
+
+force_reload() {
+    restart
+}
+
+configtest() {
+  $nginx -t -c $NGINX_CONF_FILE
+}
+
+rh_status() {
+    status $prog
+}
+
+rh_status_q() {
+    rh_status >/dev/null 2>&1
+}
+
+case "$1" in
+    start)
+        rh_status_q && exit 0
+        $1
+        ;;
+    stop)
+        rh_status_q || exit 0
+        $1
+        ;;
+    restart|configtest)
+        $1
+        ;;
+    reload)
+        rh_status_q || exit 7
+        $1
+        ;;
+    force-reload)
+        force_reload
+        ;;
+    status)
+        rh_status
+        ;;
+    condrestart|try-restart)
+        rh_status_q || exit 0
+            ;;
+    *)
+        echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
+        exit 2
+esac
diff --git a/infrastructure-provisioning/src/project/templates/squid.conf b/infrastructure-provisioning/src/project/templates/squid.conf
new file mode 100644
index 0000000..0129e00
--- /dev/null
+++ b/infrastructure-provisioning/src/project/templates/squid.conf
@@ -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.
+#
+# ******************************************************************************
+
+auth_param basic program LDAP_AUTH_PATH -b "LDAP_DN" -D "LDAP_SERVICE_USERNAME,LDAP_DN" -w LDAP_SERVICE_PASSWORD -f uid=%s LDAP_HOST
+
+acl DLab_user_src_subnet src PROXY_SUBNET
+VPC_CIDRS
+ALLOWED_CIDRS
+
+
+acl SSL_ports port 443
+acl Safe_ports port 80          # http
+acl Safe_ports port 21          # ftp
+acl Safe_ports port 22          # ssh
+acl Safe_ports port 443         # https
+acl Safe_ports port 70          # gopher
+acl Safe_ports port 210         # wais
+acl Safe_ports port 1025-65535  # unregistered ports
+acl Safe_ports port 280         # http-mgmt
+acl Safe_ports port 488         # gss-http
+acl Safe_ports port 591         # filemaker
+acl Safe_ports port 777         # multiling http
+acl CONNECT method CONNECT
+
+acl ldap-auth proxy_auth EDGE_USER_NAME
+
+http_access deny !Safe_ports
+http_access allow localhost manager
+http_access deny manager
+http_access allow DLab_user_src_subnet
+http_access allow AllowedCIDRS ldap-auth
+http_access allow localhost
+http_access deny all
+
+http_port 3128
+
+cache deny all
+cache_dir null /tmp
+coredump_dir /var/spool/squid
+
+refresh_pattern ^ftp:           1440    20%     10080
+refresh_pattern ^gopher:        1440    0%      1440
+refresh_pattern -i (/cgi-bin/|\?) 0     0%      0
+refresh_pattern .               0       20%     4320
diff --git a/infrastructure-provisioning/src/ssn/files/aws/mongo_roles.json b/infrastructure-provisioning/src/ssn/files/aws/mongo_roles.json
index 68b31b6..70eb16e 100644
--- a/infrastructure-provisioning/src/ssn/files/aws/mongo_roles.json
+++ b/infrastructure-provisioning/src/ssn/files/aws/mongo_roles.json
@@ -267,7 +267,9 @@
       "/api/infrastructure/backup",
       "/roleManagement",
       "/api/settings",
-      "/user/settings"
+      "/user/settings",
+      "/api/project",
+      "/api/endpoint"
     ],
     "groups": [
       "$anyuser"
diff --git a/infrastructure-provisioning/src/ssn/files/azure/mongo_roles.json b/infrastructure-provisioning/src/ssn/files/azure/mongo_roles.json
index fc11971..58cadb3 100644
--- a/infrastructure-provisioning/src/ssn/files/azure/mongo_roles.json
+++ b/infrastructure-provisioning/src/ssn/files/azure/mongo_roles.json
@@ -227,7 +227,9 @@
       "/api/infrastructure/backup",
       "/roleManagement",
       "/api/settings",
-      "/user/settings"
+      "/user/settings",
+      "/api/project",
+      "/api/endpoint"
     ],
     "groups": [
       "$anyuser"
diff --git a/infrastructure-provisioning/src/ssn/files/gcp/mongo_roles.json b/infrastructure-provisioning/src/ssn/files/gcp/mongo_roles.json
index 47ce720..0dceb3c 100644
--- a/infrastructure-provisioning/src/ssn/files/gcp/mongo_roles.json
+++ b/infrastructure-provisioning/src/ssn/files/gcp/mongo_roles.json
@@ -227,7 +227,9 @@
       "/api/infrastructure/backup",
       "/roleManagement",
       "/api/settings",
-      "/user/settings"
+      "/user/settings",
+      "/api/project",
+      "/api/endpoint"
     ],
     "groups": [
       "$anyuser"
diff --git a/infrastructure-provisioning/src/ssn/scripts/configure_billing.py b/infrastructure-provisioning/src/ssn/scripts/configure_billing.py
index ef05e8a..7d07b50 100644
--- a/infrastructure-provisioning/src/ssn/scripts/configure_billing.py
+++ b/infrastructure-provisioning/src/ssn/scripts/configure_billing.py
@@ -68,8 +68,6 @@
         if args.cloud_provider == 'aws':
             if args.aws_job_enabled == 'true':
                 args.tag_resource_id =  'resourceTags' + ':' + args.tag_resource_id
-            elif args.aws_job_enabled == 'false':
-                args.tag_resource_id = 'user' + ':' + args.tag_resource_id
             config_orig = config_orig.replace('<BILLING_BUCKET_NAME>', args.billing_bucket)
             config_orig = config_orig.replace('<AWS_JOB_ENABLED>', args.aws_job_enabled)
             config_orig = config_orig.replace('<REPORT_PATH>', args.report_path)
diff --git a/infrastructure-provisioning/src/tensor/fabfile.py b/infrastructure-provisioning/src/tensor/fabfile.py
index 4509ad4..b183d28 100644
--- a/infrastructure-provisioning/src/tensor/fabfile.py
+++ b/infrastructure-provisioning/src/tensor/fabfile.py
@@ -33,7 +33,7 @@
 
 # Main function for provisioning notebook server
 def run():
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'], os.environ['request_id'])
+    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,
@@ -61,7 +61,7 @@
 
 # Main function for terminating exploratory environment
 def terminate():
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'], os.environ['request_id'])
+    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,
@@ -76,7 +76,7 @@
 
 # Main function for stopping notebook server
 def stop():
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'], os.environ['request_id'])
+    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,
@@ -91,7 +91,7 @@
 
 # Main function for starting notebook server
 def start():
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'], os.environ['request_id'])
+    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,
@@ -107,7 +107,7 @@
 
 # Main function for configuring notebook server after deploying DataEngine service
 def configure():
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -125,7 +125,7 @@
 
 # Main function for installing additional libraries for notebook
 def install_libs():
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -142,7 +142,7 @@
 
 # Main function for get available libraries for notebook
 def list_libs():
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -159,7 +159,7 @@
 
 # Main function for manage git credentials on notebook
 def git_creds():
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -176,7 +176,7 @@
 
 # Main function for creating image from notebook
 def create_image():
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -193,7 +193,7 @@
 
 # Main function for deleting existing notebook image
 def terminate_image():
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -210,7 +210,7 @@
 
 # Main function for reconfiguring Spark for notebook
 def reconfigure_spark():
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
@@ -226,7 +226,7 @@
 
 # Main function for checking inactivity status
 def check_inactivity():
-    local_log_filename = "{}_{}_{}.log".format(os.environ['conf_resource'], os.environ['edge_user_name'],
+    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',
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/module/aws/AdapterS3File.java b/services/billing-aws/src/main/java/com/epam/dlab/module/aws/AdapterS3File.java
index 9ae8768..9dc7e07 100644
--- a/services/billing-aws/src/main/java/com/epam/dlab/module/aws/AdapterS3File.java
+++ b/services/billing-aws/src/main/java/com/epam/dlab/module/aws/AdapterS3File.java
@@ -43,8 +43,6 @@
 import java.io.InputStreamReader;
 import java.util.Date;
 import java.util.List;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
 
 /**
  * The adapter for S3 file system of Amazon.
@@ -222,12 +220,6 @@
 	private InputStream fileInputStream = null;
 
 	/**
-	 * Zip input stream.
-	 */
-	@JsonIgnore
-	private ZipInputStream zipInputStream;
-
-	/**
 	 * Reader for adapter.
 	 */
 	@JsonIgnore
@@ -239,7 +231,7 @@
 		if (getMode() == Mode.READ) {
 			setLastModificationDate();
 			clientS3 = getAmazonClient();
-			S3FileList s3files = new S3FileList(awsJobEnabled,bucket, getModuleData());
+			S3FileList s3files = new S3FileList(awsJobEnabled, bucket, getModuleData());
 			filelist = s3files.getFiles(clientS3);
 			currentFileIndex = (filelist.isEmpty() ? -1 : 0);
 			fileInputStream = null;
@@ -271,29 +263,18 @@
 		}
 		entryName = filename;
 		LOGGER.debug("Open a next entry in file {}", filename);
-
-		if (fileInputStream == null) {
-			openZipFile(filename);
+		reader = new BufferedReader(new InputStreamReader(getFileStream()));
+		try {
+			getModuleData().setId(filename);
+			getModuleData().setModificationDate(lastModificationDate);
+			getModuleData().set(DATA_KEY_LAST_LOADED_FILE, filename);
+			getModuleData().set(DATA_KEY_LAST_MODIFICATION_DATE, lastModificationDate);
+			getModuleData().store();
+		} catch (Exception e) {
+			throw new AdapterException(e.getLocalizedMessage(), e);
 		}
-		if (openZipEntry(filename)) {
-			return true;
-		}
-
-		if (reader != null) {
-			try {
-				getModuleData().setId(filename);
-				getModuleData().setModificationDate(lastModificationDate);
-				getModuleData().set(DATA_KEY_LAST_LOADED_FILE, filename);
-				getModuleData().set(DATA_KEY_LAST_MODIFICATION_DATE, lastModificationDate);
-				getModuleData().store();
-			} catch (Exception e) {
-				throw new AdapterException(e.getLocalizedMessage(), e);
-			}
-		}
-
-		reader = null;
 		currentFileIndex++;
-		return openNextEntry();
+		return false;
 	}
 
 	@Override
@@ -303,7 +284,7 @@
 
 	@Override
 	public void close() throws AdapterException {
-		closeZipFile(getCurrentFileName());
+		closeFile(getCurrentFileName());
 	}
 
 	@Override
@@ -389,60 +370,12 @@
 	}
 
 	/**
-	 * Open a zip file.
-	 *
-	 * @param filename file name.
-	 * @throws AdapterException
-	 */
-	private void openZipFile(String filename) throws AdapterException {
-		LOGGER.debug("Open a zip file {}", filename);
-		try {
-			fileInputStream = getFileStream();
-		} catch (Exception e) {
-			throw new AdapterException("Cannot open file " + filename + ". " + e.getLocalizedMessage(), e);
-		}
-
-		try {
-			zipInputStream = new ZipInputStream(fileInputStream);
-		} catch (Exception e) {
-			throw new AdapterException(String.format(CANNOT_READ_FILE_FORMAT, filename, e.getLocalizedMessage()), e);
-		}
-	}
-
-	/**
-	 * Open a next entry in zip file.
-	 *
-	 * @param filename file name.
-	 * @return <b>true</b> if a next entry has been opened.
-	 * @throws AdapterException
-	 */
-	private boolean openZipEntry(String filename) throws AdapterException {
-		ZipEntry entry;
-		try {
-			entry = zipInputStream.getNextEntry();
-			if (entry != null) {
-				entryName = filename + ":" + entry.getName();
-				LOGGER.debug("Next the zip entry {}", entry.getName());
-				reader = new BufferedReader(new InputStreamReader(zipInputStream));
-			} else {
-				LOGGER.debug("Zip file have no more entries");
-			}
-		} catch (Exception e) {
-			throw new AdapterException(String.format(CANNOT_READ_FILE_FORMAT, filename, e.getLocalizedMessage()), e);
-		}
-		if (entry == null) {
-			closeZipFile(filename);
-		}
-		return (entry != null);
-	}
-
-	/**
 	 * Close a zip file.
 	 *
 	 * @param filename file name.
 	 * @throws AdapterException
 	 */
-	private void closeZipFile(String filename) throws AdapterException {
+	private void closeFile(String filename) throws AdapterException {
 		if (fileInputStream != null) {
 			try {
 				fileInputStream.close();
diff --git a/services/billing-aws/src/main/java/com/epam/dlab/module/aws/S3FileList.java b/services/billing-aws/src/main/java/com/epam/dlab/module/aws/S3FileList.java
index b286a43..021497e 100644
--- a/services/billing-aws/src/main/java/com/epam/dlab/module/aws/S3FileList.java
+++ b/services/billing-aws/src/main/java/com/epam/dlab/module/aws/S3FileList.java
@@ -50,7 +50,7 @@
 	/**
 	 * Report suffix without date.
 	 */
-	private static final String REPORT_SUFIX = ".csv.zip";
+	private static final String REPORT_SUFIX = ".csv";
 	/**
 	 * Date regex for YYYYMMDD
 	 */
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/UserInstanceDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/UserInstanceDTO.java
index a4a3e47..5dae5ef 100644
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/UserInstanceDTO.java
+++ b/services/dlab-model/src/main/java/com/epam/dlab/dto/UserInstanceDTO.java
@@ -28,10 +28,7 @@
 import lombok.Data;
 
 import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
 
 /**
  * Stores info about the user notebook.
@@ -51,6 +48,10 @@
 	private String imageName;
 	@JsonProperty("version")
 	private String imageVersion;
+	@JsonProperty("project")
+	private String project;
+	@JsonProperty("endpoint")
+	private String endpoint;
 	@JsonProperty("template_name")
 	private String templateName;
 	@JsonProperty
@@ -75,6 +76,8 @@
 	private LocalDateTime lastActivity;
 	@JsonProperty("cluster_config")
 	private List<ClusterConfig> clusterConfig;
+	@JsonProperty
+	private Map<String, String> tags;
 
 	/**
 	 * Sets the user login name.
@@ -145,6 +148,11 @@
 		return this;
 	}
 
+	public UserInstanceDTO withProject(String project) {
+		setProject(project);
+		return this;
+	}
+
 	/**
 	 * Sets a list of user's computational resources for notebook.
 	 */
@@ -160,4 +168,14 @@
 		setLibs(libs);
 		return this;
 	}
+
+	public UserInstanceDTO withEndpoint(String endpoint) {
+		setEndpoint(endpoint);
+		return this;
+	}
+
+	public UserInstanceDTO withTags(Map<String, String> tags) {
+		setTags(tags);
+		return this;
+	}
 }
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/AwsComputationalResource.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/AwsComputationalResource.java
index 928733d..8a268c5 100644
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/AwsComputationalResource.java
+++ b/services/dlab-model/src/main/java/com/epam/dlab/dto/aws/computational/AwsComputationalResource.java
@@ -31,6 +31,7 @@
 import java.time.LocalDateTime;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Stores info about the user's computational resources for notebook.
@@ -62,10 +63,10 @@
 									String instanceId, String masterShape, String slaveShape, Boolean slaveSpot,
 									Integer slaveSpotPctPrice, String slaveNumber, String version,
 									List<ResourceURL> resourceURL, LocalDateTime lastActivity,
-									List<ClusterConfig> config) {
+									List<ClusterConfig> config, Map<String, String> tags) {
 
 		super(computationalName, computationalId, imageName, templateName, status, uptime, schedulerJobData,
-				reuploadKeyRequired, resourceURL, lastActivity);
+				reuploadKeyRequired, resourceURL, lastActivity, tags);
 		this.instanceId = instanceId;
 		this.masterShape = masterShape;
 		this.slaveShape = slaveShape;
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/computational/ComputationalBase.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/base/computational/ComputationalBase.java
index 0b233b5..f33e0ec 100644
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/computational/ComputationalBase.java
+++ b/services/dlab-model/src/main/java/com/epam/dlab/dto/base/computational/ComputationalBase.java
@@ -36,6 +36,9 @@
 	@JsonProperty("notebook_template_name")
 	private String notebookTemplateName;
 
+	@JsonProperty("project_name")
+	private String project;
+
 	public String getComputationalName() {
 		return computationalName;
 	}
@@ -75,6 +78,15 @@
 		return self;
 	}
 
+	public T withProject(String project) {
+		this.project = project;
+		return self;
+	}
+
+	public String getProject() {
+		return project;
+	}
+
 	@Override
 	public ToStringHelper toStringHelper(Object self) {
 		return super.toStringHelper(self)
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/project/ProjectEdgeInfo.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/base/project/ProjectEdgeInfo.java
new file mode 100644
index 0000000..0bf1c20
--- /dev/null
+++ b/services/dlab-model/src/main/java/com/epam/dlab/dto/base/project/ProjectEdgeInfo.java
@@ -0,0 +1,28 @@
+package com.epam.dlab.dto.base.project;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ProjectEdgeInfo {
+	@JsonInclude(JsonInclude.Include.NON_EMPTY)
+	private String id;
+
+	@JsonProperty("instance_id")
+	private String instanceId;
+
+	@JsonProperty
+	private String hostname;
+
+	@JsonProperty("public_ip")
+	private String publicIp;
+
+	@JsonProperty
+	private String ip;
+
+	@JsonProperty("key_name")
+	private String keyName;
+}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/base/project/ProjectResult.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/base/project/ProjectResult.java
new file mode 100644
index 0000000..c1e6827
--- /dev/null
+++ b/services/dlab-model/src/main/java/com/epam/dlab/dto/base/project/ProjectResult.java
@@ -0,0 +1,15 @@
+package com.epam.dlab.dto.base.project;
+
+import com.epam.dlab.dto.StatusBaseDTO;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ProjectResult extends StatusBaseDTO<ProjectResult> {
+	private ProjectEdgeInfo edgeInfo;
+	@JsonProperty("project_name")
+	private String projectName;
+
+}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/SparkStandaloneClusterResource.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/SparkStandaloneClusterResource.java
index 50d2c48..82f5660 100644
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/SparkStandaloneClusterResource.java
+++ b/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/SparkStandaloneClusterResource.java
@@ -32,6 +32,7 @@
 import java.time.LocalDateTime;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 @Data
 @EqualsAndHashCode(callSuper = true)
@@ -51,10 +52,10 @@
 										  SchedulerJobDTO schedulerJobData, boolean reuploadKeyRequired,
 										  String dataEngineInstanceCount, String dataEngineInstanceShape,
 										  List<ResourceURL> resourceURL, LocalDateTime lastActivity,
-										  List<ClusterConfig> config) {
+										  List<ClusterConfig> config, Map<String, String> tags) {
 
 		super(computationalName, computationalId, imageName, templateName, status, uptime, schedulerJobData,
-				reuploadKeyRequired, resourceURL, lastActivity);
+				reuploadKeyRequired, resourceURL, lastActivity, tags);
 		this.dataEngineInstanceCount = dataEngineInstanceCount;
 		this.dataEngineInstanceShape = dataEngineInstanceShape;
 		this.config = config;
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/UserComputationalResource.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/UserComputationalResource.java
index 14f2b4a..678025f 100644
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/UserComputationalResource.java
+++ b/services/dlab-model/src/main/java/com/epam/dlab/dto/computational/UserComputationalResource.java
@@ -31,6 +31,7 @@
 import java.time.LocalDateTime;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 @Data
 @NoArgsConstructor
@@ -63,11 +64,12 @@
 	@JsonProperty("instance_id")
 	private String instanceId;
 	protected List<ClusterConfig> config;
+	private Map<String,String> tags;
 
 	public UserComputationalResource(String computationalName, String computationalId, String imageName,
 									 String templateName, String status, Date uptime, SchedulerJobDTO schedulerData,
 									 boolean reuploadKeyRequired, List<ResourceURL> resourceUrl,
-									 LocalDateTime lastActivity) {
+									 LocalDateTime lastActivity, Map<String,String> tags) {
 		this.computationalName = computationalName;
 		this.computationalId = computationalId;
 		this.imageName = imageName;
@@ -78,6 +80,7 @@
 		this.reuploadKeyRequired = reuploadKeyRequired;
 		this.resourceUrl = resourceUrl;
 		this.lastActivity = lastActivity;
+		this.tags = tags;
 	}
 
 	public DataEngineType getDataEngineType() {
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryBaseDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryBaseDTO.java
index fe97f95..6550320 100644
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryBaseDTO.java
+++ b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryBaseDTO.java
@@ -24,32 +24,47 @@
 import com.google.common.base.MoreObjects.ToStringHelper;
 
 public class ExploratoryBaseDTO<T extends ExploratoryBaseDTO<?>> extends ResourceEnvBaseDTO<T> {
-    @SuppressWarnings("unchecked")
-    private final T self = (T) this;
-    @JsonProperty("notebook_image")
-    private String notebookImage;
+	@SuppressWarnings("unchecked")
+	private final T self = (T) this;
+	@JsonProperty("notebook_image")
+	private String notebookImage;
+	@JsonProperty("project_name")
+	private String project;
 
-    public String getNotebookImage() {
-        return notebookImage;
-    }
+	public String getNotebookImage() {
+		return notebookImage;
+	}
 
-    public void setNotebookImage(String notebookImage) {
-        this.notebookImage = notebookImage;
-    }
+	public void setNotebookImage(String notebookImage) {
+		this.notebookImage = notebookImage;
+	}
 
-    public T withNotebookImage(String notebookImage) {
-        setNotebookImage(notebookImage);
-        return self;
-    }
+	public T withNotebookImage(String notebookImage) {
+		setNotebookImage(notebookImage);
+		return self;
+	}
 
-    @Override
-    public ToStringHelper toStringHelper(Object self) {
-        return super.toStringHelper(self)
-                .add("notebookImage", notebookImage);
-    }
+	public T withProject(String project) {
+		setProject(project);
+		return self;
+	}
 
-    @Override
-    public String toString() {
-        return toStringHelper(this).toString();
-    }
+	@Override
+	public ToStringHelper toStringHelper(Object self) {
+		return super.toStringHelper(self)
+				.add("notebookImage", notebookImage);
+	}
+
+	public String getProject() {
+		return project;
+	}
+
+	public void setProject(String project) {
+		this.project = project;
+	}
+
+	@Override
+	public String toString() {
+		return toStringHelper(this).toString();
+	}
 }
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryCreateDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryCreateDTO.java
index 9eca961..7f87951 100644
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryCreateDTO.java
+++ b/services/dlab-model/src/main/java/com/epam/dlab/dto/exploratory/ExploratoryCreateDTO.java
@@ -24,6 +24,7 @@
 import com.google.common.base.MoreObjects.ToStringHelper;
 
 import java.util.List;
+import java.util.Map;
 
 public class ExploratoryCreateDTO<T extends ExploratoryCreateDTO<?>> extends ExploratoryBaseDTO<T> {
 
@@ -36,6 +37,10 @@
 	private String imageName;
 	@JsonProperty("spark_configurations")
 	private List<ClusterConfig> clusterConfig;
+	@JsonProperty("tags")
+	private Map<String, String> tags;
+	@JsonProperty("endpoint_name")
+	private String endpoint;
 
 	/**
 	 * Return the list of GIT credentials.
@@ -67,6 +72,16 @@
 		return self;
 	}
 
+	public T withTags(Map<String, String> tags) {
+		this.tags = tags;
+		return self;
+	}
+
+	public T withEndpoint(String endpoint) {
+		this.endpoint = endpoint;
+		return self;
+	}
+
 	public String getImageName() {
 		return imageName;
 	}
@@ -80,6 +95,14 @@
 		return self;
 	}
 
+	public String getEndpoint() {
+		return endpoint;
+	}
+
+	public void setEndpoint(String endpoint) {
+		this.endpoint = endpoint;
+	}
+
 	public List<ClusterConfig> getClusterConfig() {
 		return clusterConfig;
 	}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/computational/GcpComputationalResource.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/computational/GcpComputationalResource.java
index 061fa06..b56bbd8 100644
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/computational/GcpComputationalResource.java
+++ b/services/dlab-model/src/main/java/com/epam/dlab/dto/gcp/computational/GcpComputationalResource.java
@@ -31,6 +31,7 @@
 import java.time.LocalDateTime;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 /**
  * Stores info about the user's computational resources for notebook.
@@ -61,9 +62,10 @@
 									SchedulerJobDTO schedulerJobData, boolean reuploadKeyRequired,
 									String instanceId, String masterShape, String slaveShape, String slaveNumber,
 									String masterNumber, String preemptibleNumber, String version,
-									List<ResourceURL> resourceURL, LocalDateTime lastActivity) {
+									List<ResourceURL> resourceURL, LocalDateTime lastActivity,
+									Map<String, String> tags) {
 		super(computationalName, computationalId, imageName, templateName, status, uptime, schedulerJobData,
-				reuploadKeyRequired, resourceURL, lastActivity);
+				reuploadKeyRequired, resourceURL, lastActivity, tags);
 		this.instanceId = instanceId;
 		this.masterShape = masterShape;
 		this.slaveShape = slaveShape;
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/project/ProjectActionDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/project/ProjectActionDTO.java
new file mode 100644
index 0000000..1634c11
--- /dev/null
+++ b/services/dlab-model/src/main/java/com/epam/dlab/dto/project/ProjectActionDTO.java
@@ -0,0 +1,13 @@
+package com.epam.dlab.dto.project;
+
+import com.epam.dlab.dto.ResourceBaseDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor
+public class ProjectActionDTO extends ResourceBaseDTO<ProjectActionDTO> {
+	@JsonProperty("project_name")
+	private final String name;
+}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/project/ProjectCreateDTO.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/project/ProjectCreateDTO.java
new file mode 100644
index 0000000..a933f0b
--- /dev/null
+++ b/services/dlab-model/src/main/java/com/epam/dlab/dto/project/ProjectCreateDTO.java
@@ -0,0 +1,16 @@
+package com.epam.dlab.dto.project;
+
+import com.epam.dlab.dto.ResourceBaseDTO;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Builder;
+import lombok.Data;
+
+@Data
+@Builder
+public class ProjectCreateDTO extends ResourceBaseDTO<ProjectCreateDTO> {
+	private final String key;
+	@JsonProperty("project_name")
+	private final String name;
+	@JsonProperty("project_tag")
+	private final String tag;
+}
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/dto/status/EnvResource.java b/services/dlab-model/src/main/java/com/epam/dlab/dto/status/EnvResource.java
index 84e33f9..3f5aef2 100644
--- a/services/dlab-model/src/main/java/com/epam/dlab/dto/status/EnvResource.java
+++ b/services/dlab-model/src/main/java/com/epam/dlab/dto/status/EnvResource.java
@@ -42,14 +42,17 @@
 	private String name;
 	@JsonProperty
 	private ResourceType resourceType;
+	@JsonProperty("project_name")
+	private String project;
 	@JsonDeserialize(using = IsoLocalDateTimeDeSerializer.class)
 	@JsonProperty
 	private LocalDateTime lastActivity;
 
-	public EnvResource(String id, String name, ResourceType resourceType) {
+	public EnvResource(String id, String name, ResourceType resourceType, String project) {
 		this.id = id;
 		this.name = name;
 		this.resourceType = resourceType;
+		this.project = project;
 	}
 
 	/**
diff --git a/services/dlab-model/src/main/java/com/epam/dlab/model/exploratory/Exploratory.java b/services/dlab-model/src/main/java/com/epam/dlab/model/exploratory/Exploratory.java
index 923adab..4b67f70 100644
--- a/services/dlab-model/src/main/java/com/epam/dlab/model/exploratory/Exploratory.java
+++ b/services/dlab-model/src/main/java/com/epam/dlab/model/exploratory/Exploratory.java
@@ -34,5 +34,8 @@
 	private final String templateName;
 	private final String shape;
 	private final String imageName;
+	private final String endpoint;
+	private final String project;
+	private final String exploratoryTag;
 	private final List<ClusterConfig> clusterConfig;
 }
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/UserInfo.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/UserInfo.java
index 8668a91..b0c05bf 100644
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/UserInfo.java
+++ b/services/dlab-webapp-common/src/main/java/com/epam/dlab/auth/UserInfo.java
@@ -67,7 +67,7 @@
     }
 
     @JsonProperty("roles")
-    public Collection<String> getRoles() {
+    public Set<String> getRoles() {
         return roles;
     }
 
@@ -121,6 +121,8 @@
         return newInfo;
     }
 
+
+
     public boolean isAwsUser() {
         return awsUser;
     }
@@ -161,6 +163,8 @@
 
     }
 
+
+
     @Override
     public int hashCode() {
         return Objects.hash(username,
diff --git a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/ValidationExceptionMapper.java b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/ValidationExceptionMapper.java
index 49ce81f..700ce4d 100644
--- a/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/ValidationExceptionMapper.java
+++ b/services/dlab-webapp-common/src/main/java/com/epam/dlab/rest/mappers/ValidationExceptionMapper.java
@@ -36,7 +36,7 @@
 		final String errors =
 				exception.getConstraintViolations()
 						.stream().map(violation -> ConstraintMessage.getMessage(violation, invocable))
-						.collect(Collectors.joining());
+						.collect(Collectors.joining(","));
 		return Response.status(Response.Status.BAD_REQUEST)
 				.entity(new ErrorDTO(Response.Status.BAD_REQUEST.getStatusCode(), errors))
 				.type(MediaType.APPLICATION_JSON)
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/ProvisioningServiceApplication.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/ProvisioningServiceApplication.java
index 4f063c6..2353f2d 100644
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/ProvisioningServiceApplication.java
+++ b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/ProvisioningServiceApplication.java
@@ -102,6 +102,7 @@
 		jersey.register(injector.getInstance(BackupResource.class));
 		jersey.register(injector.getInstance(KeyResource.class));
 		jersey.register(injector.getInstance(CallbackHandlerResource.class));
+		jersey.register(injector.getInstance(ProjectResource.class));
 
 	}
 }
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CommandExecutorMockAsync.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CommandExecutorMockAsync.java
index 5af48e3..7277961 100644
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CommandExecutorMockAsync.java
+++ b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/CommandExecutorMockAsync.java
@@ -294,8 +294,8 @@
 	private void action(String user, DockerAction action) {
 		String resourceType = parser.getResourceType();
 
-		String prefixFileName = (Lists.newArrayList("edge", "dataengine", "dataengine-service").contains
-				(resourceType) ? resourceType : "notebook") + "_";
+		String prefixFileName = (Lists.newArrayList("project", "edge", "dataengine", "dataengine-service")
+				.contains(resourceType) ? resourceType : "notebook") + "_";
 		String templateFileName = "mock_response/" + cloudProvider.getName() + '/' + prefixFileName +
 				action.toString() + JSON_FILE_ENDING;
 		responseFileName = getAbsolutePath(parser.getResponsePath(), prefixFileName + user + "_" +
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/DockerCommands.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/DockerCommands.java
index 6a329ea..dec60af 100644
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/DockerCommands.java
+++ b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/commands/DockerCommands.java
@@ -35,6 +35,7 @@
             .pipe(UnixCommand.grep("base", "-v"))
             .pipe(UnixCommand.grep("ssn", "-v"))
             .pipe(UnixCommand.grep("edge", "-v"))
+            .pipe(UnixCommand.grep("project", "-v"))
             .toCMD();
 
     String GET_RUNNING_CONTAINERS_FOR_USER = "docker ps --format \"{{.Names}}\" -f name=%s";
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ProjectCallbackHandler.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ProjectCallbackHandler.java
new file mode 100644
index 0000000..71a21e1
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/core/response/handlers/ProjectCallbackHandler.java
@@ -0,0 +1,47 @@
+package com.epam.dlab.backendapi.core.response.handlers;
+
+import com.epam.dlab.auth.SystemUserInfoService;
+import com.epam.dlab.backendapi.core.commands.DockerAction;
+import com.epam.dlab.dto.UserInstanceStatus;
+import com.epam.dlab.dto.base.project.ProjectEdgeInfo;
+import com.epam.dlab.dto.base.project.ProjectResult;
+import com.epam.dlab.exceptions.DlabException;
+import com.epam.dlab.rest.client.RESTService;
+import com.fasterxml.jackson.databind.JsonNode;
+
+import java.io.IOException;
+
+public class ProjectCallbackHandler extends ResourceCallbackHandler<ProjectResult> {
+
+
+	private final String callbackUri;
+	private final String projectName;
+
+	public ProjectCallbackHandler(SystemUserInfoService systemUserInfoService, RESTService selfService, String user,
+								  String uuid, DockerAction action, String callbackUri, String projectName) {
+		super(systemUserInfoService, selfService, user, uuid, action);
+		this.callbackUri = callbackUri;
+		this.projectName = projectName;
+	}
+
+	@Override
+	protected String getCallbackURI() {
+		return callbackUri;
+	}
+
+	@Override
+	protected ProjectResult parseOutResponse(JsonNode resultNode, ProjectResult baseStatus) {
+		baseStatus.setProjectName(projectName);
+		if (resultNode != null && getAction() == DockerAction.CREATE
+				&& UserInstanceStatus.of(baseStatus.getStatus()) != UserInstanceStatus.FAILED) {
+			try {
+				final ProjectEdgeInfo projectEdgeInfo = mapper.readValue(resultNode.toString(), ProjectEdgeInfo.class);
+				baseStatus.setEdgeInfo(projectEdgeInfo);
+			} catch (IOException e) {
+				throw new DlabException("Cannot parse the EDGE info in JSON: " + e.getLocalizedMessage(), e);
+			}
+		}
+
+		return baseStatus;
+	}
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java
index 3ba4d42..bfaac79 100644
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java
+++ b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java
@@ -29,9 +29,11 @@
 import com.epam.dlab.backendapi.core.commands.ICommandExecutor;
 import com.epam.dlab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
 import com.epam.dlab.backendapi.core.response.handlers.dao.FileSystemCallbackHandlerDao;
-import com.epam.dlab.backendapi.service.RestoreCallbackHandlerService;
 import com.epam.dlab.backendapi.service.CheckInactivityService;
+import com.epam.dlab.backendapi.service.ProjectService;
+import com.epam.dlab.backendapi.service.RestoreCallbackHandlerService;
 import com.epam.dlab.backendapi.service.impl.CheckInactivityServiceImpl;
+import com.epam.dlab.backendapi.service.impl.ProjectServiceImpl;
 import com.epam.dlab.backendapi.service.impl.RestoreCallbackHandlerServiceImpl;
 import com.epam.dlab.constants.ServiceConsts;
 import com.epam.dlab.mongo.MongoService;
@@ -75,5 +77,6 @@
 		bind(CallbackHandlerDao.class).to(FileSystemCallbackHandlerDao.class);
 		bind(RestoreCallbackHandlerService.class).to(RestoreCallbackHandlerServiceImpl.class);
 		bind(CheckInactivityService.class).to(CheckInactivityServiceImpl.class);
+		bind(ProjectService.class).to(ProjectServiceImpl.class);
 	}
 }
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProvisioningDevModule.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProvisioningDevModule.java
index 3ec1035..9817a65 100644
--- a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProvisioningDevModule.java
+++ b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/modules/ProvisioningDevModule.java
@@ -31,9 +31,11 @@
 import com.epam.dlab.backendapi.core.commands.ICommandExecutor;
 import com.epam.dlab.backendapi.core.response.handlers.dao.CallbackHandlerDao;
 import com.epam.dlab.backendapi.core.response.handlers.dao.FileSystemCallbackHandlerDao;
+import com.epam.dlab.backendapi.service.ProjectService;
 import com.epam.dlab.backendapi.service.RestoreCallbackHandlerService;
 import com.epam.dlab.backendapi.service.CheckInactivityService;
 import com.epam.dlab.backendapi.service.impl.CheckInactivityServiceImpl;
+import com.epam.dlab.backendapi.service.impl.ProjectServiceImpl;
 import com.epam.dlab.backendapi.service.impl.RestoreCallbackHandlerServiceImpl;
 import com.epam.dlab.constants.ServiceConsts;
 import com.epam.dlab.mongo.MongoService;
@@ -91,6 +93,7 @@
 		bind(CallbackHandlerDao.class).to(FileSystemCallbackHandlerDao.class);
 		bind(RestoreCallbackHandlerService.class).to(RestoreCallbackHandlerServiceImpl.class);
 		bind(CheckInactivityService.class).to(CheckInactivityServiceImpl.class);
+		bind(ProjectService.class).to(ProjectServiceImpl.class);
 	}
 
 	/**
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java
new file mode 100644
index 0000000..005ad9f
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java
@@ -0,0 +1,57 @@
+package com.epam.dlab.backendapi.resources;
+
+import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.service.ProjectService;
+import com.epam.dlab.dto.project.ProjectActionDTO;
+import com.epam.dlab.dto.project.ProjectCreateDTO;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Path("infrastructure/project")
+public class ProjectResource {
+	private final ProjectService projectService;
+
+	@Inject
+	public ProjectResource(ProjectService projectService) {
+		this.projectService = projectService;
+	}
+
+	@Path("/create")
+	@POST
+	@Consumes(MediaType.APPLICATION_JSON)
+	@Produces(MediaType.APPLICATION_JSON)
+	public Response createProject(@Auth UserInfo userInfo, ProjectCreateDTO dto) {
+		return Response.ok(projectService.create(userInfo, dto)).build();
+	}
+
+	@Path("/terminate")
+	@POST
+	@Consumes(MediaType.APPLICATION_JSON)
+	@Produces(MediaType.APPLICATION_JSON)
+	public Response terminateProject(@Auth UserInfo userInfo, ProjectActionDTO dto) {
+		return Response.ok(projectService.terminate(userInfo, dto)).build();
+	}
+
+	@Path("/start")
+	@POST
+	@Consumes(MediaType.APPLICATION_JSON)
+	@Produces(MediaType.APPLICATION_JSON)
+	public Response startProject(@Auth UserInfo userInfo, ProjectActionDTO dto) {
+		return Response.ok(projectService.start(userInfo, dto)).build();
+	}
+
+	@Path("/stop")
+	@POST
+	@Consumes(MediaType.APPLICATION_JSON)
+	@Produces(MediaType.APPLICATION_JSON)
+	public Response stopProject(@Auth UserInfo userInfo, ProjectActionDTO dto) {
+		return Response.ok(projectService.stop(userInfo, dto)).build();
+	}
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/ProjectService.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/ProjectService.java
new file mode 100644
index 0000000..65d4b70
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/ProjectService.java
@@ -0,0 +1,16 @@
+package com.epam.dlab.backendapi.service;
+
+import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.dto.project.ProjectActionDTO;
+import com.epam.dlab.dto.project.ProjectCreateDTO;
+
+public interface ProjectService {
+
+	String create(UserInfo userInfo, ProjectCreateDTO projectCreateDTO);
+
+	String terminate(UserInfo userInfo, ProjectActionDTO dto);
+
+	String start(UserInfo userInfo, ProjectActionDTO dto);
+
+	String stop(UserInfo userInfo, ProjectActionDTO dto);
+}
diff --git a/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java
new file mode 100644
index 0000000..adc1a7a
--- /dev/null
+++ b/services/provisioning-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java
@@ -0,0 +1,83 @@
+package com.epam.dlab.backendapi.service.impl;
+
+import com.epam.dlab.auth.SystemUserInfoService;
+import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.ProvisioningServiceApplicationConfiguration;
+import com.epam.dlab.backendapi.core.commands.*;
+import com.epam.dlab.backendapi.core.response.folderlistener.FolderListenerExecutor;
+import com.epam.dlab.backendapi.core.response.handlers.ProjectCallbackHandler;
+import com.epam.dlab.backendapi.service.ProjectService;
+import com.epam.dlab.dto.ResourceBaseDTO;
+import com.epam.dlab.dto.project.ProjectActionDTO;
+import com.epam.dlab.dto.project.ProjectCreateDTO;
+import com.epam.dlab.rest.client.RESTService;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class ProjectServiceImpl implements ProjectService {
+	private static final String PROJECT_IMAGE = "docker.dlab-project";
+	private static final String EDGE_IMAGE = "docker.dlab-edge";
+	@Inject
+	protected RESTService selfService;
+	@Inject
+	protected SystemUserInfoService systemUserInfoService;
+	@Inject
+	private ProvisioningServiceApplicationConfiguration configuration;
+	@Inject
+	private FolderListenerExecutor folderListenerExecutor;
+	@Inject
+	private ICommandExecutor commandExecutor;
+	@Inject
+	private CommandBuilder commandBuilder;
+
+	@Override
+	public String create(UserInfo userInfo, ProjectCreateDTO dto) {
+		return executeDocker(userInfo, dto, DockerAction.CREATE, dto.getName(), "project", PROJECT_IMAGE);
+	}
+
+	@Override
+	public String terminate(UserInfo userInfo, ProjectActionDTO dto) {
+		return executeDocker(userInfo, dto, DockerAction.TERMINATE, dto.getName(), "project", PROJECT_IMAGE);
+	}
+
+	@Override
+	public String start(UserInfo userInfo, ProjectActionDTO dto) {
+		return executeDocker(userInfo, dto, DockerAction.START, dto.getName(), "edge", EDGE_IMAGE);
+	}
+
+	@Override
+	public String stop(UserInfo userInfo, ProjectActionDTO dto) {
+		return executeDocker(userInfo, dto, DockerAction.STOP, dto.getName(), "edge", EDGE_IMAGE);
+	}
+
+	private String executeDocker(UserInfo userInfo, ResourceBaseDTO dto, DockerAction action, String projectName,
+								 String resourceType, String image) {
+		String uuid = DockerCommands.generateUUID();
+
+		folderListenerExecutor.start(configuration.getKeyLoaderDirectory(),
+				configuration.getKeyLoaderPollTimeout(),
+				new ProjectCallbackHandler(systemUserInfoService, selfService, userInfo.getName(), uuid,
+						action, "/api/project/status", projectName));
+
+		RunDockerCommand runDockerCommand = new RunDockerCommand()
+				.withInteractive()
+				.withName(String.join("_", projectName, resourceType, action.toString()))
+				.withVolumeForRootKeys(configuration.getKeyDirectory())
+				.withVolumeForResponse(configuration.getKeyLoaderDirectory())
+				.withVolumeForLog(configuration.getDockerLogDirectory(), resourceType)
+				.withResource(resourceType)
+				.withRequestId(uuid)
+				.withConfKeyName(configuration.getAdminKey())
+				.withImage(image)
+				.withAction(action);
+
+		try {
+			commandExecutor.executeAsync(userInfo.getName(), uuid, commandBuilder.buildCommand(runDockerCommand, dto));
+		} catch (JsonProcessingException e) {
+			e.printStackTrace();
+		}
+		return uuid;
+	}
+}
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_create.json b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_create.json
index 4de53d0..7d7bad5 100644
--- a/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_create.json
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/notebook_create.json
@@ -14,6 +14,7 @@
           "description": "Ungit"
         }
       ],
+      "instance_id": "${INSTANCE_ID}",
       "notebook_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-nb-${EXPLORATORY_NAME}-${NOTEBOOK_ID}",
       "Action": "Create new notebook server",
       "master_keyname": "${CONF_KEY_NAME}"
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/project_create.json b/services/provisioning-service/src/main/resources/mock_response/gcp/project_create.json
new file mode 100644
index 0000000..9f59b6d
--- /dev/null
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/project_create.json
@@ -0,0 +1,56 @@
+{
+  "status": "ok",
+  "response": {
+    "result": {
+      "tunnel_port": "22",
+      "full_edge_conf": {
+        "edge_service_account_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge",
+        "fw_edge_egress_internal": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge-egress-internal",
+        "dlab_ssh_user": "dlab-user",
+        "ps_role_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-ps",
+        "fw_ps_egress_public": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-ps-egress-public",
+        "private_ip": "10.10.0.3",
+        "fw_ps_ingress": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-ps-ingress",
+        "ssh_key_path": "/root/keys/BDCC-DSS-POC.pem",
+        "zone": "us-west1-a ",
+        "fw_edge_egress_public": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge-egress-public",
+        "ami_name": "/projects/ubuntu-os-cloud/global/images/ubuntu-1604-xenial-v20170721",
+        "edge_role_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge",
+        "private_subnet_prefix": "24",
+        "subnet_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-subnet",
+        "vpc_cidr": "10.10.0.0/16",
+        "key_name": "${CONF_KEY_NAME}",
+        "service_base_name": "${CONF_SERVICE_BASE_NAME}",
+        "static_address_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-ip",
+        "fw_ps_egress_private": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-ps-egress-private",
+        "vpc_name": "${CONF_SERVICE_BASE_NAME}-ssn-vpc",
+        "static_ip": "104.198.5.3",
+        "bucket_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-bucket",
+        "fw_edge_ingress_public": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge-ingress-public",
+        "ps_service_account_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-ps",
+        "firewall_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge-firewall",
+        "region": "us-west1",
+        "fw_common_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-ps",
+        "instance_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge",
+        "user_keyname": "${EDGE_USER_NAME}",
+        "edge_user_name": "${EDGE_USER_NAME}",
+        "private_subnet_cidr": "10.10.16.0/24",
+        "fw_edge_ingress_internal": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-edge-ingress-internal",
+        "vpc_selflink": "https://www.googleapis.com/compute/v1/projects/or2-msq-epmc-dlab-t1iylu/global/networks/${CONF_SERVICE_BASE_NAME}-ssn-vpc",
+        "instance_size": "n1-standard-1",
+        "notebook_firewall_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-nb-firewall"
+      },
+      "key_name": "BDCC-DSS-POC",
+      "hostname": "104.198.5.3",
+      "public_ip": "104.198.5.3",
+      "ip": "10.10.0.3",
+      "Action": "Create new EDGE server",
+      "user_own_bucket_name": "${CONF_SERVICE_BASE_NAME}-${EDGE_USER_NAME}-bucket",
+      "socks_port": "1080",
+      "notebook_subnet": "10.10.16.0/24",
+      "project_name" : "${PROJECT_NAME}"
+    },
+    "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+  },
+  "request_id": "${REQUEST_ID}"
+}
\ No newline at end of file
diff --git a/services/provisioning-service/src/main/resources/mock_response/gcp/project_terminate.json b/services/provisioning-service/src/main/resources/mock_response/gcp/project_terminate.json
new file mode 100644
index 0000000..7420ded
--- /dev/null
+++ b/services/provisioning-service/src/main/resources/mock_response/gcp/project_terminate.json
@@ -0,0 +1,12 @@
+{
+  "status": "ok",
+  "response": {
+    "result": {
+      "Action": "Terminate edge node",
+      "project_tag": "prj1",
+      "service_base_name": "${CONF_SERVICE_BASE_NAME}"
+    },
+    "log": "/var/log/dlab/edge/edge_${EDGE_USER_NAME}_${REQUEST_ID}.log"
+  },
+  "request_id": "${REQUEST_ID}"
+}
\ No newline at end of file
diff --git a/services/self-service/pom.xml b/services/self-service/pom.xml
index 5521958..9ce6b72 100644
--- a/services/self-service/pom.xml
+++ b/services/self-service/pom.xml
@@ -91,6 +91,22 @@
         </dependency>
 
         <dependency>
+            <groupId>io.swagger.core.v3</groupId>
+            <artifactId>swagger-core</artifactId>
+            <version>2.0.1</version>
+        </dependency>
+        <dependency>
+            <groupId>io.swagger.core.v3</groupId>
+            <artifactId>swagger-jaxrs2</artifactId>
+            <version>2.0.1</version>
+        </dependency>
+        <dependency>
+            <groupId>io.swagger.core.v3</groupId>
+            <artifactId>swagger-integration</artifactId>
+            <version>2.0.1</version>
+        </dependency>
+
+        <dependency>
             <groupId>com.jcraft</groupId>
             <artifactId>jsch</artifactId>
             <version>${com.jcraft.jsch.version}</version>
diff --git a/services/self-service/self-service.yml b/services/self-service/self-service.yml
index 855950d..0f2dcc1 100644
--- a/services/self-service/self-service.yml
+++ b/services/self-service/self-service.yml
@@ -81,7 +81,7 @@
   - type: https
     port: 8443
     certAlias: dlab
-    validateCerts: true
+    validateCerts: false
     keyStorePath: ${KEY_STORE_PATH}
     keyStorePassword: ${KEY_STORE_PASSWORD}
     trustStorePath: ${TRUST_STORE_PATH}
@@ -92,7 +92,7 @@
   - type: https
     port: 8444
     certAlias: dlab
-    validateCerts: true
+    validateCerts: false
     keyStorePath: ${KEY_STORE_PATH}
     keyStorePassword: ${KEY_STORE_PASSWORD}
     trustStorePath: ${TRUST_STORE_PATH}
@@ -105,6 +105,7 @@
   loggers:
     com.epam: TRACE
     com.novemberain: ERROR
+    io.swagger.v3: DEBUG
   appenders:
 <#if DEV_MODE == "true">
   - type: console
@@ -157,8 +158,12 @@
     enabled: true
     cron: "0 0 * ? * * *"
   checkUserQuoteScheduler:
-    enabled: true
+    enabled: false
     cron: "0 0 * ? * * *"
+  checkProjectQuoteScheduler:
+    enabled: true
+    cron: "0 * * ? * * *"
+
 
 guacamole:
   connectionProtocol: ssh
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/SelfServiceApplication.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/SelfServiceApplication.java
index 979464f..8cc143e 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/SelfServiceApplication.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/SelfServiceApplication.java
@@ -51,8 +51,11 @@
 import io.dropwizard.jetty.BiDiGzipHandler;
 import io.dropwizard.setup.Bootstrap;
 import io.dropwizard.setup.Environment;
-import io.federecio.dropwizard.swagger.SwaggerBundle;
-import io.federecio.dropwizard.swagger.SwaggerBundleConfiguration;
+import io.swagger.v3.jaxrs2.integration.resources.OpenApiResource;
+import io.swagger.v3.oas.integration.SwaggerConfiguration;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Contact;
+import io.swagger.v3.oas.models.info.Info;
 import lombok.extern.slf4j.Slf4j;
 import org.eclipse.jetty.server.Handler;
 import org.eclipse.jetty.server.Server;
@@ -60,6 +63,8 @@
 
 import javax.servlet.DispatcherType;
 import java.util.EnumSet;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * Self Service based on Dropwizard application.
@@ -92,12 +97,14 @@
 		bootstrap.addBundle(new TemplateConfigBundle(
 				new TemplateConfigBundleConfiguration().fileIncludePath(ServiceUtils.getConfPath())
 		));
-		bootstrap.addBundle(new SwaggerBundle<SelfServiceApplicationConfiguration>() {
+
+		/*bootstrap.addBundle(new SwaggerBundle<SelfServiceApplicationConfiguration>() {
 			@Override
-			protected SwaggerBundleConfiguration getSwaggerBundleConfiguration(SelfServiceApplicationConfiguration configuration) {
+			protected SwaggerBundleConfiguration getSwaggerBundleConfiguration(SelfServiceApplicationConfiguration
+			configuration) {
 				return configuration.getSwaggerConfiguration();
 			}
-		});
+		});*/
 	}
 
 	@Override
@@ -173,6 +180,27 @@
 		jersey.register(injector.getInstance(UserGroupResource.class));
 		jersey.register(injector.getInstance(UserRoleResource.class));
 		jersey.register(injector.getInstance(ApplicationSettingResource.class));
+		jersey.register(injector.getInstance(EndpointResource.class));
+		jersey.register(injector.getInstance(ProjectResource.class));
+		jersey.register(injector.getInstance(ProjectCallback.class));
+		OpenAPI oas = new OpenAPI();
+		Info info = new Info()
+				.title("Hello World API")
+				.version("2.1")
+				.description("RESTful greetings for you.")
+				.termsOfService("http://example.com/terms")
+				.contact(new Contact().email("john@example.com"));
+
+		oas.info(info);
+		SwaggerConfiguration oasConfig = new SwaggerConfiguration()
+				.openAPI(oas)
+				//.readAllResources(false)
+				.prettyPrint(true)
+				.resourceClasses(Stream.of(ProjectResource.class.getName(),
+						EndpointResource.class.getName())
+						.collect(Collectors.toSet()));
+		environment.jersey().register(new OpenApiResource()
+				.openApiConfiguration(oasConfig));
 	}
 
 	private void disableGzipHandlerForGuacamoleServlet(Server server) {
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/Project.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/Project.java
new file mode 100644
index 0000000..5a1e5d4
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/annotation/Project.java
@@ -0,0 +1,12 @@
+package com.epam.dlab.backendapi.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+@Target(ElementType.PARAMETER)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Project {
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/auth/SelfServiceSecurityAuthorizer.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/auth/SelfServiceSecurityAuthorizer.java
index 9b348e9..2d93b74 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/auth/SelfServiceSecurityAuthorizer.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/auth/SelfServiceSecurityAuthorizer.java
@@ -29,6 +29,6 @@
 public class SelfServiceSecurityAuthorizer implements Authorizer<UserInfo> {
 	@Override
 	public boolean authorize(UserInfo principal, String role) {
-		return UserRoles.checkAccess(principal, RoleType.PAGE, role);
+		return UserRoles.checkAccess(principal, RoleType.PAGE, role, principal.getRoles());
 	}
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseBillingDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseBillingDAO.java
index 29319c7..23785b4 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseBillingDAO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseBillingDAO.java
@@ -58,6 +58,7 @@
 	public static final String COST_TOTAL = "cost_total";
 	public static final String FULL_REPORT = "full_report";
 
+	private static final String PROJECT = "project";
 	private static final String MASTER_NODE_SHAPE = "master_node_shape";
 	private static final String SLAVE_NODE_SHAPE = "slave_node_shape";
 	private static final String TOTAL_INSTANCE_NUMBER = "total_instance_number";
@@ -75,6 +76,8 @@
 	protected SettingsDAO settings;
 	@Inject
 	private UserSettingsDAO userSettingsDAO;
+	@Inject
+	private ProjectDAO projectDAO;
 
 	protected Map<String, ShapeInfo> getShapes(List<String> shapeNames) {
 		FindIterable<Document> userInstances = getUserInstances();
@@ -109,6 +112,13 @@
 	}
 
 	@Override
+	public Double getProjectCost(String project) {
+		final List<Bson> pipeline = Arrays.asList(match(eq(PROJECT, project)),
+				group(null, sum(TOTAL_FIELD_NAME, COST_FIELD)));
+		return aggregateBillingData(pipeline);
+	}
+
+	@Override
 	public int getBillingQuoteUsed() {
 		return toPercentage(() -> settings.getMaxBudget(), getTotalCost());
 	}
@@ -131,6 +141,14 @@
 				.isPresent();
 	}
 
+	@Override
+	public boolean isProjectQuoteReached(String project) {
+		final Double projectCost = getProjectCost(project);
+		return projectDAO.getAllowedBudget(project)
+				.filter(allowedBudget -> projectCost.intValue() != 0 && allowedBudget <= projectCost)
+				.isPresent();
+	}
+
 	protected String getUserOrDefault(String user) {
 		return StringUtils.isNotBlank(user) ? user : SHARED_RESOURCE_NAME;
 	}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseDAO.java
index 77f3284..034011a 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseDAO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BaseDAO.java
@@ -371,7 +371,7 @@
 	 */
 	protected <T> Optional<T> findOne(String collection, Bson condition, Class<T> clazz) {
 		Optional<Document> doc = findOne(collection, condition);
-		return doc.isPresent() ? Optional.ofNullable(convertFromDocument(doc.get(), clazz)) : Optional.empty();
+		return doc.map(document -> convertFromDocument(document, clazz));
 	}
 
 	/**
@@ -384,7 +384,7 @@
 	 */
 	protected <T> Optional<T> findOne(String collection, Bson condition, Bson projection, Class<T> clazz) {
 		Optional<Document> doc = findOne(collection, condition, projection);
-		return doc.isPresent() ? Optional.ofNullable(convertFromDocument(doc.get(), clazz)) : Optional.empty();
+		return doc.map(document -> convertFromDocument(document, clazz));
 	}
 
 	/**
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BillingDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BillingDAO.java
index 079c7ea..1498012 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BillingDAO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/BillingDAO.java
@@ -27,6 +27,8 @@
 
 	Double getUserCost(String user);
 
+	Double getProjectCost(String project);
+
 	int getBillingQuoteUsed();
 
 	int getBillingUserQuoteUsed(String user);
@@ -35,5 +37,7 @@
 
 	boolean isUserQuoteReached(String user);
 
+	boolean isProjectQuoteReached(String project);
+
 	Document getReport(UserInfo userInfo, T filter);
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/EndpointDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/EndpointDAO.java
new file mode 100644
index 0000000..9b85bc3
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/EndpointDAO.java
@@ -0,0 +1,15 @@
+package com.epam.dlab.backendapi.dao;
+
+import com.epam.dlab.backendapi.domain.EndpointDTO;
+
+import java.util.List;
+import java.util.Optional;
+
+public interface EndpointDAO {
+	List<EndpointDTO> getEndpoints();
+	Optional<EndpointDTO> get(String name);
+
+	void create(EndpointDTO endpointDTO);
+
+	void remove(String name);
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/EndpointDAOImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/EndpointDAOImpl.java
new file mode 100644
index 0000000..413d06d
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/EndpointDAOImpl.java
@@ -0,0 +1,38 @@
+package com.epam.dlab.backendapi.dao;
+
+import com.epam.dlab.backendapi.domain.EndpointDTO;
+import org.bson.conversions.Bson;
+
+import java.util.List;
+import java.util.Optional;
+
+import static com.mongodb.client.model.Filters.regex;
+
+public class EndpointDAOImpl extends BaseDAO implements EndpointDAO {
+
+	private static final String ENDPOINTS_COLLECTION = "endpoints";
+
+	@Override
+	public List<EndpointDTO> getEndpoints() {
+		return find(ENDPOINTS_COLLECTION, EndpointDTO.class);
+	}
+
+	@Override
+	public Optional<EndpointDTO> get(String name) {
+		return findOne(ENDPOINTS_COLLECTION, endpointCondition(name), EndpointDTO.class);
+	}
+
+	@Override
+	public void create(EndpointDTO endpointDTO) {
+		insertOne(ENDPOINTS_COLLECTION, endpointDTO);
+	}
+
+	@Override
+	public void remove(String name) {
+		deleteOne(ENDPOINTS_COLLECTION, endpointCondition(name));
+	}
+
+	private Bson endpointCondition(String name) {
+		return regex("name", "^" + name, "i");
+	}
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/EnvDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/EnvDAO.java
index 2fb7b9a..b2c6c2b 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/EnvDAO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/EnvDAO.java
@@ -69,9 +69,10 @@
 	private static final String COMPUTATIONAL_STATUS_FILTER = COMPUTATIONAL_RESOURCES + FIELD_SET_DELIMETER + STATUS;
 	private static final String COMPUTATIONAL_SPOT = "slave_node_spot";
 	private static final String IMAGE = "image";
+	private static final String PROJECT = "project";
 
 	private static final Bson INCLUDE_EDGE_FIELDS = include(INSTANCE_ID, EDGE_STATUS, EDGE_PUBLIC_IP);
-	private static final Bson INCLUDE_EXP_FIELDS = include(INSTANCE_ID, STATUS,
+	private static final Bson INCLUDE_EXP_FIELDS = include(INSTANCE_ID, STATUS, PROJECT,
 			COMPUTATIONAL_RESOURCES + "." + INSTANCE_ID, COMPUTATIONAL_RESOURCES + "." + IMAGE, COMPUTATIONAL_STATUS,
 			EXPLORATORY_NAME, COMPUTATIONAL_RESOURCES + "." + ComputationalDAO.COMPUTATIONAL_NAME);
 	private static final Bson INCLUDE_EXP_UPDATE_FIELDS = include(EXPLORATORY_NAME, INSTANCE_ID, STATUS,
@@ -92,12 +93,13 @@
 		List<EnvResource> hostList = new ArrayList<>();
 		List<EnvResource> clusterList = new ArrayList<>();
 
-		getEdgeNode(user).ifPresent(edge -> addResource(hostList, edge, EDGE_STATUS, ResourceType.EDGE, null));
+		//getEdgeNode(user).ifPresent(edge -> addResource(hostList, edge, EDGE_STATUS, ResourceType.EDGE, null));
 
 		stream(find(USER_INSTANCES, eq(USER, user), fields(INCLUDE_EXP_FIELDS, excludeId())))
 				.forEach(exp -> {
 					final String exploratoryName = exp.getString(EXPLORATORY_NAME);
-					addResource(hostList, exp, STATUS, ResourceType.EXPLORATORY, exploratoryName);
+					final String project = exp.getString(PROJECT);
+					addResource(hostList, exp, STATUS, ResourceType.EXPLORATORY, exploratoryName, project);
 					addComputationalResources(hostList, clusterList, exp, exploratoryName);
 				});
 		return new EnvResourceList()
@@ -113,31 +115,16 @@
 				.collect(Collectors.toList());
 	}
 
-	private List<EnvResource> getRunningEnvResources(Document ui) {
-		final String exploratoryName = ui.getString(EXPLORATORY_NAME);
-		final List<EnvResource> envResources = getComputationalResources(ui)
-				.stream()
-				.filter(comp -> RUNNING.toString().equals(comp.getString(STATUS)))
-				.map(comp -> toEnvResource(String.join("_", exploratoryName,
-						comp.getString(COMPUTATIONAL_NAME)), comp.getString(INSTANCE_ID),
-						ResourceType.COMPUTATIONAL))
-				.collect(Collectors.toList());
-		if (UserInstanceStatus.of(ui.getString(STATUS)) == RUNNING) {
-			envResources.add(toEnvResource(exploratoryName, ui.getString(INSTANCE_ID),
-					ResourceType.EXPLORATORY));
-		}
-		return envResources;
-	}
-
-	private EnvResource toEnvResource(String name, String instanceId, ResourceType resType) {
-		return new EnvResource(instanceId, name, resType);
+	private EnvResource toEnvResource(String name, String instanceId, ResourceType resType, String project) {
+		return new EnvResource(instanceId, name, resType, project);
 	}
 
 	@SuppressWarnings("unchecked")
 	private void addComputationalResources(List<EnvResource> hostList, List<EnvResource> clusterList, Document exp,
 										   String exploratoryName) {
+		final String project = exp.getString(PROJECT);
 		getComputationalResources(exp)
-				.forEach(comp -> addComputational(hostList, clusterList, exploratoryName, comp));
+				.forEach(comp -> addComputational(hostList, clusterList, exploratoryName, comp, project));
 	}
 
 	private List<Document> getComputationalResources(Document userInstanceDocument) {
@@ -145,12 +132,12 @@
 	}
 
 	private void addComputational(List<EnvResource> hostList, List<EnvResource> clusterList, String exploratoryName,
-								  Document computational) {
+								  Document computational, String project) {
 		final List<EnvResource> resourceList = DataEngineType.CLOUD_SERVICE ==
 				DataEngineType.fromDockerImageName(computational.getString(IMAGE)) ? clusterList :
 				hostList;
 		addResource(resourceList, computational, STATUS, ResourceType.COMPUTATIONAL,
-				String.join("_", exploratoryName, computational.getString(COMPUTATIONAL_NAME)));
+				String.join("_", exploratoryName, computational.getString(COMPUTATIONAL_NAME)), project);
 	}
 
 	/**
@@ -522,13 +509,13 @@
 	 * @param resourceType    type if resource EDGE/NOTEBOOK
 	 */
 	private void addResource(List<EnvResource> list, Document document, String statusFieldName,
-							 ResourceType resourceType, String name) {
+							 ResourceType resourceType, String name, String project) {
 		LOGGER.trace("Add resource from {}", document);
 		getInstanceId(document).ifPresent(instanceId ->
 				Optional.ofNullable(UserInstanceStatus.of(document.getString(statusFieldName)))
 						.filter(s -> s.in(CONFIGURING, CREATING, RUNNING, STARTING, STOPPED, STOPPING, TERMINATING) ||
 								(FAILED == s && ResourceType.EDGE == resourceType))
-						.ifPresent(s -> list.add(toEnvResource(name, instanceId, resourceType))));
+						.ifPresent(s -> list.add(toEnvResource(name, instanceId, resourceType, project))));
 	}
 
 	private boolean notEmpty(List<EnvResource> hostList) {
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ExploratoryDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ExploratoryDAO.java
index ea3cef0..499ca20 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ExploratoryDAO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ExploratoryDAO.java
@@ -67,6 +67,7 @@
 	private static final String EXPLORATORY_PRIVATE_IP = "private_ip";
 	public static final String EXPLORATORY_NOT_FOUND_MSG = "Exploratory for user %s with name %s not found";
 	private static final String EXPLORATORY_LAST_ACTIVITY = "last_activity";
+	private static final String PROJECT = "project";
 
 	public ExploratoryDAO() {
 		log.info("{} is initialized", getClass().getSimpleName());
@@ -129,6 +130,10 @@
 		return getUserInstances(and(eq(USER, user), eq(STATUS, UserInstanceStatus.RUNNING.toString())), false);
 	}
 
+	public List<UserInstanceDTO> fetchRunningExploratoryFieldsForProject(String project) {
+		return getUserInstances(and(eq(PROJECT, project), eq(STATUS, UserInstanceStatus.RUNNING.toString())), false);
+	}
+
 	/**
 	 * Finds and returns the info of all user's notebooks whose status is present among predefined ones.
 	 *
@@ -169,6 +174,20 @@
 				false);
 	}
 
+	public List<UserInstanceDTO> fetchProjectExploratoriesWhereStatusIn(String project,
+																		List<UserInstanceStatus> exploratoryStatuses,
+																		UserInstanceStatus... computationalStatuses) {
+		final List<String> exploratoryStatusList = statusList(exploratoryStatuses);
+		final List<String> computationalStatusList = statusList(computationalStatuses);
+		return getUserInstances(
+				and(
+						eq(PROJECT, project),
+						or(in(STATUS, exploratoryStatusList),
+								in(COMPUTATIONAL_RESOURCES + "." + STATUS, computationalStatusList))
+				),
+				false);
+	}
+
 	/**
 	 * Finds and returns the info of all user's notebooks whose status is absent among predefined ones.
 	 *
@@ -185,6 +204,17 @@
 				false);
 	}
 
+	public List<UserInstanceDTO> fetchProjectExploratoriesWhereStatusNotIn(String project,
+																		   UserInstanceStatus... statuses) {
+		final List<String> statusList = statusList(statuses);
+		return getUserInstances(
+				and(
+						eq(USER, project),
+						not(in(STATUS, statusList))
+				),
+				false);
+	}
+
 	private List<UserInstanceDTO> getUserInstances(Bson condition, boolean computationalFieldsRequired) {
 		return stream(getCollection(USER_INSTANCES)
 				.find(condition)
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAO.java
new file mode 100644
index 0000000..d18393c
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAO.java
@@ -0,0 +1,36 @@
+package com.epam.dlab.backendapi.dao;
+
+import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.domain.ProjectDTO;
+import com.epam.dlab.dto.base.project.ProjectEdgeInfo;
+import com.epam.dlab.backendapi.domain.UpdateProjectDTO;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+public interface ProjectDAO {
+	List<ProjectDTO> getProjects();
+
+	List<ProjectDTO> getProjectsWithStatus(ProjectDTO.Status status);
+
+	List<ProjectDTO> getUserProjectsWithStatus(UserInfo userInfo, ProjectDTO.Status status);
+
+	void create(ProjectDTO projectDTO);
+
+	void updateStatus(String projectName, ProjectDTO.Status status);
+
+	void updateEdgeInfoAndStatus(String projectName, ProjectEdgeInfo edgeInfo, ProjectDTO.Status status);
+
+	Optional<ProjectDTO> get(String name);
+
+	boolean update(UpdateProjectDTO projectDTO);
+
+	void remove(String name);
+
+	Optional<Integer> getAllowedBudget(String project);
+
+	void updateBudget(String project, Integer budget);
+
+	boolean isAnyProjectAssigned(Set<String> groups);
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAOImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAOImpl.java
new file mode 100644
index 0000000..5525e3d
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/ProjectDAOImpl.java
@@ -0,0 +1,112 @@
+package com.epam.dlab.backendapi.dao;
+
+import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.domain.ProjectDTO;
+import com.epam.dlab.backendapi.domain.UpdateProjectDTO;
+import com.epam.dlab.dto.base.edge.EdgeInfo;
+import com.epam.dlab.dto.base.project.ProjectEdgeInfo;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Sets;
+import com.google.inject.Inject;
+import com.mongodb.BasicDBObject;
+import com.mongodb.client.result.UpdateResult;
+import org.bson.Document;
+import org.bson.conversions.Bson;
+
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+
+import static com.mongodb.client.model.Filters.*;
+
+public class ProjectDAOImpl extends BaseDAO implements ProjectDAO {
+
+	private static final String PROJECTS_COLLECTION = "Projects";
+	private static final String GROUPS = "groups";
+	private static final String ENDPOINTS = "endpoints";
+	private static final String STATUS_FIELD = "status";
+	private static final String EDGE_INFO_FIELD = "edgeInfo";
+
+	private final UserGroupDao userGroupDao;
+
+	@Inject
+	public ProjectDAOImpl(UserGroupDao userGroupDao) {
+		this.userGroupDao = userGroupDao;
+	}
+
+
+	@Override
+	public List<ProjectDTO> getProjects() {
+		return find(PROJECTS_COLLECTION, ProjectDTO.class);
+	}
+
+	@Override
+	public List<ProjectDTO> getProjectsWithStatus(ProjectDTO.Status status) {
+		return find(PROJECTS_COLLECTION, eq(STATUS_FIELD, status.toString()), ProjectDTO.class);
+	}
+
+	@Override
+	public List<ProjectDTO> getUserProjectsWithStatus(UserInfo userInfo, ProjectDTO.Status status) {
+		return find(PROJECTS_COLLECTION, and(in(GROUPS, Sets.union(userGroupDao.getUserGroups(userInfo.getName()),
+				userInfo.getRoles())), eq(STATUS_FIELD, status.toString())), ProjectDTO.class);
+	}
+
+	@Override
+	public void create(ProjectDTO projectDTO) {
+		insertOne(PROJECTS_COLLECTION, projectDTO);
+	}
+
+	@Override
+	public void updateStatus(String projectName, ProjectDTO.Status status) {
+		updateOne(PROJECTS_COLLECTION, projectCondition(projectName),
+				new Document(SET, new Document(STATUS_FIELD, status.toString())));
+	}
+
+	@Override
+	public void updateEdgeInfoAndStatus(String projectName, ProjectEdgeInfo edgeInfo, ProjectDTO.Status status) {
+		BasicDBObject dbObject = new BasicDBObject();
+		dbObject.put(STATUS_FIELD, status.toString());
+		dbObject.put(EDGE_INFO_FIELD, convertToBson(edgeInfo));
+		final UpdateResult updateResult = updateOne(PROJECTS_COLLECTION, projectCondition(projectName),
+				new Document(SET, dbObject));
+		System.out.println(updateResult);
+	}
+
+	@Override
+	public Optional<ProjectDTO> get(String name) {
+		return findOne(PROJECTS_COLLECTION, projectCondition(name), ProjectDTO.class);
+	}
+
+	@Override
+	public boolean update(UpdateProjectDTO projectDTO) {
+		BasicDBObject updateProject = new BasicDBObject();
+		updateProject.put(GROUPS, projectDTO.getGroups());
+		updateProject.put(ENDPOINTS, projectDTO.getEndpoints());
+		return updateOne(PROJECTS_COLLECTION, projectCondition(projectDTO.getName()),
+				new Document(SET, updateProject)).getMatchedCount() > 0L;
+	}
+
+	@Override
+	public void remove(String name) {
+		deleteOne(PROJECTS_COLLECTION, projectCondition(name));
+	}
+
+	@Override
+	public Optional<Integer> getAllowedBudget(String project) {
+		return get(project).map(ProjectDTO::getBudget);
+	}
+
+	@Override
+	public void updateBudget(String project, Integer budget) {
+		updateOne(PROJECTS_COLLECTION, projectCondition(project), new Document(SET, new Document("budget", budget)));
+	}
+
+	@Override
+	public boolean isAnyProjectAssigned(Set<String> groups) {
+		return !Iterables.isEmpty(find(PROJECTS_COLLECTION, in(GROUPS, groups)));
+	}
+
+	private Bson projectCondition(String name) {
+		return eq("name", name);
+	}
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/SchedulerJobDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/SchedulerJobDAO.java
index 99f6b1b..597d0f9 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/SchedulerJobDAO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/SchedulerJobDAO.java
@@ -131,11 +131,13 @@
 				and(
 						eq(STATUS, status.toString()),
 						schedulerNotNullCondition(),
-						eq(CONSIDER_INACTIVITY_FLAG, true),
-						or(eq(COMPUTATIONAL_RESOURCES, Collections.emptyList()),
-								and(ne(COMPUTATIONAL_RESOURCES, Collections.emptyList()),
-										Filters.elemMatch(COMPUTATIONAL_RESOURCES,
-												lte(LAST_ACTIVITY, lastActivity))))
+						or(and(eq(CONSIDER_INACTIVITY_FLAG, true),
+								or(eq(COMPUTATIONAL_RESOURCES, Collections.emptyList()),
+										and(ne(COMPUTATIONAL_RESOURCES, Collections.emptyList()),
+												Filters.elemMatch(COMPUTATIONAL_RESOURCES,
+														lte(LAST_ACTIVITY, lastActivity))))),
+								eq(CONSIDER_INACTIVITY_FLAG, false)
+						)
 				),
 				fields(excludeId(), include(USER, EXPLORATORY_NAME, SCHEDULER_DATA))))
 				.map(d -> convertFromDocument(d, SchedulerJobData.class))
@@ -159,9 +161,11 @@
 				.collect(toList());
 	}
 
-	public List<SchedulerJobData> getComputationalSchedulerDataWithOneOfStatus(UserInstanceStatus exploratoryStatus, UserInstanceStatus... statuses) {
+	public List<SchedulerJobData> getComputationalSchedulerDataWithOneOfStatus(UserInstanceStatus exploratoryStatus,
+																			   UserInstanceStatus... statuses) {
 		return stream(computationalResourcesWithScheduler(exploratoryStatus))
-				.map(doc -> computationalSchedulerData(doc, statuses).map(compResource -> toSchedulerData(doc, compResource)))
+				.map(doc -> computationalSchedulerData(doc, statuses).map(compResource -> toSchedulerData(doc,
+						compResource)))
 				.flatMap(Function.identity())
 				.collect(toList());
 	}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserGroupDao.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserGroupDao.java
index d8fb8ec..0a4dde5 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserGroupDao.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserGroupDao.java
@@ -29,4 +29,6 @@
 
 	void removeGroup(String groupId);
 
+	Set<String> getUserGroups(String user);
+
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserGroupDaoImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserGroupDaoImpl.java
index a8e5a15..350f6a2 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserGroupDaoImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/UserGroupDaoImpl.java
@@ -22,9 +22,11 @@
 import org.bson.Document;
 
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import static com.epam.dlab.backendapi.dao.MongoCollections.USER_GROUPS;
 import static com.mongodb.client.model.Filters.eq;
+import static com.mongodb.client.model.Filters.in;
 
 @Singleton
 public class UserGroupDaoImpl extends BaseDAO implements UserGroupDao {
@@ -50,4 +52,11 @@
 	public void removeGroup(String groupId) {
 		deleteOne(USER_GROUPS, eq(ID, groupId));
 	}
+
+	@Override
+	public Set<String> getUserGroups(String user) {
+		return stream(find(USER_GROUPS, in(USERS_FIELD, user)))
+				.map(document -> document.getString(ID))
+				.collect(Collectors.toSet());
+	}
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/aws/AwsBillingDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/aws/AwsBillingDAO.java
index 43f4a9c..c5e0c92 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/aws/AwsBillingDAO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/aws/AwsBillingDAO.java
@@ -84,7 +84,7 @@
     public Document getReport(UserInfo userInfo, AwsBillingFilter filter) {
         // Create filter
         List<Bson> conditions = new ArrayList<>();
-        boolean isFullReport = UserRoles.checkAccess(userInfo, RoleType.PAGE, "/api/infrastructure_provision/billing");
+        boolean isFullReport = UserRoles.checkAccess(userInfo, RoleType.PAGE, "/api/infrastructure_provision/billing", userInfo.getRoles());
         setUserFilter(userInfo, filter, isFullReport);
         addCondition(conditions, USER, filter.getUser());
         addCondition(conditions, FIELD_PRODUCT, filter.getProduct());
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/azure/AzureBillingDAO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/azure/AzureBillingDAO.java
index 5b4db2a..42bccbc 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/azure/AzureBillingDAO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/azure/AzureBillingDAO.java
@@ -57,7 +57,7 @@
 
     public Document getReport(UserInfo userInfo, AzureBillingFilter filter) {
 
-        boolean isFullReport = UserRoles.checkAccess(userInfo, RoleType.PAGE, "/api/infrastructure_provision/billing");
+        boolean isFullReport = UserRoles.checkAccess(userInfo, RoleType.PAGE, "/api/infrastructure_provision/billing", userInfo.getRoles());
         setUserFilter(userInfo, filter, isFullReport);
 
         List<Bson> matchCriteria = matchCriteria(filter);
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/gcp/GcpBillingDao.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/gcp/GcpBillingDao.java
index 492d8b5..05112a2 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/gcp/GcpBillingDao.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/dao/gcp/GcpBillingDao.java
@@ -36,6 +36,11 @@
 	}
 
 	@Override
+	public Double getProjectCost(String project) {
+		return null;
+	}
+
+	@Override
 	public int getBillingQuoteUsed() {
 		return 0;
 	}
@@ -56,6 +61,11 @@
 	}
 
 	@Override
+	public boolean isProjectQuoteReached(String project) {
+		return false;
+	}
+
+	@Override
 	public Document getReport(UserInfo userInfo, BillingFilter filter) {
 		return null;
 	}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/EndpointDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/EndpointDTO.java
new file mode 100644
index 0000000..e2cdfb3
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/EndpointDTO.java
@@ -0,0 +1,16 @@
+package com.epam.dlab.backendapi.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class EndpointDTO {
+
+	private final String name;
+	private final String url;
+	private final String account;
+	@JsonProperty("endpoint_tag")
+	private final String tag;
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ProjectDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ProjectDTO.java
new file mode 100644
index 0000000..631cc99
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/ProjectDTO.java
@@ -0,0 +1,58 @@
+package com.epam.dlab.backendapi.domain;
+
+import com.epam.dlab.dto.UserInstanceStatus;
+import com.epam.dlab.dto.base.edge.EdgeInfo;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import java.util.Set;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ProjectDTO {
+	@NotNull
+	private final String name;
+	@NotNull
+	private final Set<String> endpoints;
+	@NotNull
+	private final Set<String> groups;
+	@NotNull
+	@Pattern(regexp = "^ssh-.*", message = "Wrong key format. Key should be in openSSH format")
+	private final String key;
+	@NotNull
+	private final String tag;
+	private final Integer budget;
+	private final Status status = Status.CREATING;
+	private EdgeInfo edgeInfo;
+
+
+	public enum Status {
+		CREATING,
+		ACTIVE,
+		FAILED,
+		DELETED,
+		DELETING,
+		DEACTIVATING,
+		ACTIVATING,
+		NOT_ACTIVE;
+
+		public static Status from(UserInstanceStatus userInstanceStatus) {
+			if (userInstanceStatus == UserInstanceStatus.RUNNING) {
+				return ACTIVE;
+			} else if (userInstanceStatus == UserInstanceStatus.TERMINATED) {
+				return DELETED;
+			} else if (userInstanceStatus == UserInstanceStatus.TERMINATING) {
+				return DELETING;
+			} else if (userInstanceStatus == UserInstanceStatus.STOPPING) {
+				return DEACTIVATING;
+			} else if (userInstanceStatus == UserInstanceStatus.STOPPED) {
+				return NOT_ACTIVE;
+			} else if (userInstanceStatus == UserInstanceStatus.STARTING) {
+				return ACTIVATING;
+			}
+			return Status.valueOf(userInstanceStatus.name());
+		}
+	}
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/UpdateProjectBudgetDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/UpdateProjectBudgetDTO.java
new file mode 100644
index 0000000..72cbf05
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/UpdateProjectBudgetDTO.java
@@ -0,0 +1,13 @@
+package com.epam.dlab.backendapi.domain;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Data
+public class UpdateProjectBudgetDTO {
+	@NotNull
+	private final String project;
+	@NotNull
+	private final Integer budget;
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/UpdateProjectDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/UpdateProjectDTO.java
new file mode 100644
index 0000000..5121412
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/domain/UpdateProjectDTO.java
@@ -0,0 +1,19 @@
+package com.epam.dlab.backendapi.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.util.Set;
+
+@Data
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class UpdateProjectDTO {
+	@NotNull
+	private final String name;
+	@NotNull
+	private final Set<String> endpoints;
+	@NotNull
+	private final Set<String> groups;
+
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/BudgetLimitInterceptor.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/BudgetLimitInterceptor.java
index ebe3a54..43fdaf6 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/BudgetLimitInterceptor.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/interceptor/BudgetLimitInterceptor.java
@@ -20,6 +20,7 @@
 package com.epam.dlab.backendapi.interceptor;
 
 import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.annotation.Project;
 import com.epam.dlab.backendapi.dao.BillingDAO;
 import com.epam.dlab.exceptions.ResourceQuoteReachedException;
 import com.google.inject.Inject;
@@ -28,7 +29,10 @@
 import org.aopalliance.intercept.MethodInvocation;
 
 import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
 import java.util.Arrays;
+import java.util.Objects;
+import java.util.stream.IntStream;
 
 @Slf4j
 public class BudgetLimitInterceptor implements MethodInterceptor {
@@ -37,7 +41,7 @@
 
 	@Override
 	public Object invoke(MethodInvocation mi) throws Throwable {
-		if (userQuoteReached(mi) || billingDAO.isBillingQuoteReached()) {
+		if (projectQuoteReached(mi) || billingDAO.isBillingQuoteReached()) {
 			final Method method = mi.getMethod();
 			log.warn("Execution of method {} failed because of reaching resource limit quote", method.getName());
 			throw new ResourceQuoteReachedException("Operation can not be finished. Resource quote is reached");
@@ -54,4 +58,15 @@
 				.map(billingDAO::isUserQuoteReached)
 				.orElse(Boolean.FALSE);
 	}
+
+	private Boolean projectQuoteReached(MethodInvocation mi) {
+
+		final Parameter[] parameters = mi.getMethod().getParameters();
+		return IntStream.range(0, parameters.length)
+				.filter(i -> Objects.nonNull(parameters[i].getAnnotation(Project.class)))
+				.mapToObj(i -> (String) mi.getArguments()[i])
+				.findAny()
+				.map(billingDAO::isProjectQuoteReached)
+				.orElse(Boolean.FALSE);
+	}
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/DevModule.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/DevModule.java
index bd4a5ab..dc24362 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/DevModule.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/DevModule.java
@@ -76,6 +76,7 @@
 		bind(BackupService.class).to(BackupServiceImpl.class);
 		bind(BackupDao.class).to(BackupDaoImpl.class);
 		bind(ExploratoryService.class).to(ExploratoryServiceImpl.class);
+		bind(TagService.class).to(TagServiceImpl.class);
 		bind(InactivityService.class).to(InactivityServiceImpl.class);
 		bind(SystemUserInfoService.class).toInstance(new SystemUserInfoService() {
 			@Override
@@ -110,6 +111,10 @@
 		bind(ApplicationSettingService.class).to(ApplicationSettingServiceImpl.class);
 		bind(UserSettingService.class).to(UserSettingServiceImpl.class);
 		bind(GuacamoleService.class).to(GuacamoleServiceImpl.class);
+		bind(EndpointService.class).to(EndpointServiceImpl.class);
+		bind(EndpointDAO.class).to(EndpointDAOImpl.class);
+		bind(ProjectService.class).to(ProjectServiceImpl.class);
+		bind(ProjectDAO.class).to(ProjectDAOImpl.class);
 	}
 
 	/**
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java
index 7db5b26..4a3bc70 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/modules/ProductionModule.java
@@ -87,5 +87,10 @@
 		bind(ApplicationSettingService.class).to(ApplicationSettingServiceImpl.class);
 		bind(UserSettingService.class).to(UserSettingServiceImpl.class);
 		bind(GuacamoleService.class).to(GuacamoleServiceImpl.class);
+		bind(EndpointService.class).to(EndpointServiceImpl.class);
+		bind(EndpointDAO.class).to(EndpointDAOImpl.class);
+		bind(ProjectService.class).to(ProjectServiceImpl.class);
+		bind(ProjectDAO.class).to(ProjectDAOImpl.class);
+		bind(TagService.class).to(TagServiceImpl.class);
 	}
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/EndpointResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/EndpointResource.java
new file mode 100644
index 0000000..ff206df
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/EndpointResource.java
@@ -0,0 +1,108 @@
+package com.epam.dlab.backendapi.resources;
+
+import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.domain.EndpointDTO;
+import com.epam.dlab.backendapi.service.EndpointService;
+import com.epam.dlab.rest.dto.ErrorDTO;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.headers.Header;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+
+import javax.annotation.security.RolesAllowed;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.net.URI;
+
+@Path("endpoint")
+@RolesAllowed("/api/endpoint")
+public class EndpointResource {
+
+	private final EndpointService endpointService;
+	@Context
+	private UriInfo uriInfo;
+
+	@Inject
+	public EndpointResource(EndpointService endpointService) {
+		this.endpointService = endpointService;
+	}
+
+	@Operation(summary = "Create endpoint", tags = "endpoint")
+	@ApiResponses({
+			@ApiResponse(responseCode = "201", description = "Endpoint is successfully created",
+					headers =
+					@Header(required = true, name = "Location", description = "URI of created endpoint resource",
+							schema = @Schema(type = "string"))),
+			@ApiResponse(responseCode = "400", description = "Validation error", content = @Content(mediaType =
+					MediaType.APPLICATION_JSON,
+					schema = @Schema(implementation = ErrorDTO.class))),
+			@ApiResponse(responseCode = "409", description = "Endpoint with passed name already exist in system",
+					content = @Content(mediaType = MediaType.APPLICATION_JSON,
+							schema = @Schema(implementation = ErrorDTO.class)))
+	})
+	@Consumes(MediaType.APPLICATION_JSON)
+	@POST
+	public Response createEndpoint(@Parameter(hidden = true) @Auth UserInfo userInfo, EndpointDTO endpointDTO) {
+		endpointService.create(endpointDTO);
+		final URI uri = uriInfo.getRequestUriBuilder().path(endpointDTO.getName()).build();
+		return Response
+				.ok()
+				.location(uri)
+				.build();
+	}
+
+	@Operation(summary = "Get endpoint info", tags = "endpoint")
+	@ApiResponses({
+			@ApiResponse(responseCode = "200", description = "Return information about endpoint",
+					content = @Content(mediaType = MediaType.APPLICATION_JSON, schema =
+					@Schema(implementation = EndpointDTO.class))),
+			@ApiResponse(responseCode = "404", description = "Endpoint with passed name not found",
+					content = @Content(mediaType = MediaType.APPLICATION_JSON,
+							schema = @Schema(implementation = ErrorDTO.class)))
+	})
+	@GET
+	@Path("{name}")
+	@Produces(MediaType.APPLICATION_JSON)
+	public Response getEndpoint(@Parameter(hidden = true) @Auth UserInfo userInfo,
+								@Parameter(description = "Endpoint name")
+								@PathParam("name") String name) {
+		return Response.ok(endpointService.get(name)).build();
+	}
+
+	@Operation(summary = "Get endpoints available in system", tags = "endpoint")
+	@ApiResponses({
+			@ApiResponse(responseCode = "200", description = "Return information about endpoints",
+					content = @Content(mediaType = MediaType.APPLICATION_JSON, schema =
+					@Schema(implementation = EndpointDTO.class)))
+	})
+	@GET
+	@Produces(MediaType.APPLICATION_JSON)
+	public Response getEndpoints(@Parameter(hidden = true) @Auth UserInfo userInfo) {
+		return Response.ok(endpointService.getEndpoints()).build();
+	}
+
+
+	@Operation(summary = "Remove endpoint", tags = "endpoint")
+	@ApiResponses({
+			@ApiResponse(responseCode = "200", description = "Endpoint is successfully removed"),
+			@ApiResponse(responseCode = "404", description = "Endpoint with passed name not found",
+					content = @Content(mediaType = MediaType.APPLICATION_JSON,
+							schema = @Schema(implementation = ErrorDTO.class)))
+	})
+	@DELETE
+	@Path("{name}")
+	public Response removeEndpoint(@Parameter(hidden = true) @Auth UserInfo userInfo,
+								   @Parameter(description = "Endpoint name")
+								   @PathParam("name") String name) {
+		endpointService.remove(name);
+		return Response.ok().build();
+	}
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ExploratoryResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ExploratoryResource.java
index 897255d..d397e98 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ExploratoryResource.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ExploratoryResource.java
@@ -79,11 +79,11 @@
 						   @Valid @NotNull ExploratoryCreateFormDTO formDTO) {
 		log.debug("Creating exploratory environment {} with name {} for user {}",
 				formDTO.getImage(), formDTO.getName(), userInfo.getName());
-		if (!UserRoles.checkAccess(userInfo, RoleType.EXPLORATORY, formDTO.getImage())) {
+		if (!UserRoles.checkAccess(userInfo, RoleType.EXPLORATORY, formDTO.getImage(), userInfo.getRoles())) {
 			log.warn("Unauthorized attempt to create a {} by user {}", formDTO.getImage(), userInfo.getName());
 			throw new DlabException("You do not have the privileges to create a " + formDTO.getTemplateName());
 		}
-		String uuid = exploratoryService.create(userInfo, getExploratory(formDTO));
+		String uuid = exploratoryService.create(userInfo, getExploratory(formDTO), formDTO.getProject());
 		return Response.ok(uuid).build();
 
 	}
@@ -104,7 +104,7 @@
 						@Valid @NotNull ExploratoryActionFormDTO formDTO) {
 		log.debug("Starting exploratory environment {} for user {}", formDTO.getNotebookInstanceName(),
 				userInfo.getName());
-		return exploratoryService.start(userInfo, formDTO.getNotebookInstanceName());
+		return exploratoryService.start(userInfo, formDTO.getNotebookInstanceName(), "");
 	}
 
 	/**
@@ -167,6 +167,10 @@
 				.templateName(formDTO.getTemplateName())
 				.version(formDTO.getVersion())
 				.clusterConfig(formDTO.getClusterConfig())
-				.shape(formDTO.getShape()).build();
+				.shape(formDTO.getShape())
+				.endpoint(formDTO.getEndpoint())
+				.project(formDTO.getProject())
+				.exploratoryTag(formDTO.getExploratoryTag())
+				.build();
 	}
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/InfrastructureInfoResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/InfrastructureInfoResource.java
index 6b44c33..daec244 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/InfrastructureInfoResource.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/InfrastructureInfoResource.java
@@ -73,7 +73,7 @@
 									  @ApiParam(value = "Full version of report required", defaultValue = "0")
 									  @QueryParam("full") @DefaultValue("0") int fullReport) {
 		return infrastructureInfoService
-				.getHeathStatus(userInfo.getName(), fullReport != 0, UserRoles.isAdmin(userInfo));
+				.getHeathStatus(userInfo, fullReport != 0, UserRoles.isAdmin(userInfo));
 	}
 
 	/**
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/InfrastructureTemplateResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/InfrastructureTemplateResource.java
index 5d8adfe..14a6572 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/InfrastructureTemplateResource.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/InfrastructureTemplateResource.java
@@ -32,10 +32,7 @@
 import io.swagger.annotations.ApiParam;
 import io.swagger.annotations.Authorization;
 
-import javax.ws.rs.Consumes;
-import javax.ws.rs.GET;
-import javax.ws.rs.Path;
-import javax.ws.rs.Produces;
+import javax.ws.rs.*;
 import javax.ws.rs.core.MediaType;
 
 /**
@@ -61,11 +58,12 @@
 	 * @param userInfo user info.
 	 */
 	@GET
-	@Path("/computational_templates")
+	@Path("/{project}/computational_templates")
 	@ApiOperation("Returns list of cluster's templates")
 	public Iterable<FullComputationalTemplate> getComputationalTemplates(@ApiParam(hidden = true)
-																		 @Auth UserInfo userInfo) {
-		return infrastructureTemplateService.getComputationalTemplates(userInfo);
+																		 @Auth UserInfo userInfo,
+																		 @PathParam("project") String project) {
+		return infrastructureTemplateService.getComputationalTemplates(userInfo, project);
 	}
 
 	/**
@@ -74,10 +72,11 @@
 	 * @param userInfo user info.
 	 */
 	@GET
-	@Path("/exploratory_templates")
+	@Path("/{project}/exploratory_templates")
 	@ApiOperation("Returns list of notebook's templates")
-	public Iterable<ExploratoryMetadataDTO> getExploratoryTemplates(@ApiParam(hidden = true) @Auth UserInfo userInfo) {
-		return infrastructureTemplateService.getExploratoryTemplates(userInfo);
+	public Iterable<ExploratoryMetadataDTO> getExploratoryTemplates(@ApiParam(hidden = true) @Auth UserInfo userInfo,
+																	@PathParam("project") String project) {
+		return infrastructureTemplateService.getExploratoryTemplates(userInfo, project);
 	}
 }
 
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java
new file mode 100644
index 0000000..1d56658
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/ProjectResource.java
@@ -0,0 +1,204 @@
+package com.epam.dlab.backendapi.resources;
+
+import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.domain.ProjectDTO;
+import com.epam.dlab.backendapi.domain.UpdateProjectBudgetDTO;
+import com.epam.dlab.backendapi.domain.UpdateProjectDTO;
+import com.epam.dlab.backendapi.resources.dto.ProjectActionFormDTO;
+import com.epam.dlab.backendapi.service.ProjectService;
+import com.epam.dlab.rest.dto.ErrorDTO;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.headers.Header;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.responses.ApiResponses;
+
+import javax.annotation.security.RolesAllowed;
+import javax.validation.Valid;
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import java.net.URI;
+
+@Path("project")
+@RolesAllowed("/api/project")
+public class ProjectResource {
+	private final ProjectService projectService;
+	@Context
+	private UriInfo uriInfo;
+
+	@Inject
+	public ProjectResource(ProjectService projectService) {
+		this.projectService = projectService;
+	}
+
+
+	@Operation(summary = "Create project", tags = "project")
+	@ApiResponses({
+			@ApiResponse(responseCode = "201", description = "Project is successfully created",
+					headers =
+					@Header(required = true, name = "Location", description = "URI of created project resource",
+							schema = @Schema(type = "string"))),
+			@ApiResponse(responseCode = "400", description = "Validation error", content = @Content(mediaType =
+					MediaType.APPLICATION_JSON,
+					schema = @Schema(implementation = ErrorDTO.class))),
+			@ApiResponse(responseCode = "409", description = "Project with passed name already exist in system",
+					content = @Content(mediaType = MediaType.APPLICATION_JSON,
+							schema = @Schema(implementation = ErrorDTO.class)))
+	})
+	@POST
+	@Consumes(MediaType.APPLICATION_JSON)
+	public Response createProject(@Parameter(hidden = true) @Auth UserInfo userInfo, @Valid ProjectDTO projectDTO) {
+		projectService.create(userInfo, projectDTO);
+		final URI uri = uriInfo.getRequestUriBuilder().path(projectDTO.getName()).build();
+		return Response
+				.ok()
+				.location(uri)
+				.build();
+	}
+
+	@Operation(summary = "Start project", tags = "project")
+	@ApiResponses({
+			@ApiResponse(responseCode = "202", description = "Project is starting"),
+			@ApiResponse(responseCode = "400", description = "Validation error", content = @Content(mediaType =
+					MediaType.APPLICATION_JSON,
+					schema = @Schema(implementation = ErrorDTO.class)))
+	})
+	@Path("start")
+	@POST
+	@Consumes(MediaType.APPLICATION_JSON)
+	public Response startProject(@Parameter(hidden = true) @Auth UserInfo userInfo,
+								 @Valid ProjectActionFormDTO startProjectDto) {
+		projectService.start(userInfo, startProjectDto.getProjectName());
+		return Response
+				.accepted()
+				.build();
+	}
+
+	@Operation(summary = "Stop project", tags = "project")
+	@ApiResponses({
+			@ApiResponse(responseCode = "202", description = "Project is stopping"),
+			@ApiResponse(responseCode = "400", description = "Validation error", content = @Content(mediaType =
+					MediaType.APPLICATION_JSON,
+					schema = @Schema(implementation = ErrorDTO.class)))
+	})
+	@Path("stop")
+	@POST
+	@Consumes(MediaType.APPLICATION_JSON)
+	public Response stopProject(@Parameter(hidden = true) @Auth UserInfo userInfo,
+								@Valid ProjectActionFormDTO startProjectDto) {
+		projectService.stop(userInfo, startProjectDto.getProjectName());
+		return Response
+				.accepted()
+				.build();
+	}
+
+
+	@Operation(summary = "Get project info", tags = "project")
+	@ApiResponses({
+			@ApiResponse(responseCode = "200", description = "Return information about project",
+					content = @Content(mediaType = MediaType.APPLICATION_JSON, schema =
+					@Schema(implementation = ProjectDTO.class))),
+			@ApiResponse(responseCode = "404", description = "Project with passed name not found",
+					content = @Content(mediaType = MediaType.APPLICATION_JSON,
+							schema = @Schema(implementation = ErrorDTO.class)))
+	})
+	@GET
+	@Path("{name}")
+	@Produces(MediaType.APPLICATION_JSON)
+	public Response getProject(@Parameter(hidden = true) @Auth UserInfo userInfo,
+							   @Parameter(description = "Project name")
+							   @PathParam("name") String name) {
+		return Response
+				.ok(projectService.get(name))
+				.build();
+	}
+
+	@Operation(summary = "Get available projects", tags = "project")
+	@ApiResponses({
+			@ApiResponse(responseCode = "200", description = "Return information about projects",
+					content = @Content(mediaType = MediaType.APPLICATION_JSON, schema =
+					@Schema(implementation = ProjectDTO.class))),
+	})
+	@GET
+	@Produces(MediaType.APPLICATION_JSON)
+	public Response getProjects(@Parameter(hidden = true) @Auth UserInfo userInfo,
+								@Parameter(description = "Project name")
+								@PathParam("name") String name) {
+		return Response
+				.ok(projectService.getProjects())
+				.build();
+	}
+
+	@Operation(summary = "Get projects assigned to user", tags = "project")
+	@ApiResponses({
+			@ApiResponse(responseCode = "200", description = "Return information about projects",
+					content = @Content(mediaType = MediaType.APPLICATION_JSON, schema =
+					@Schema(implementation = ProjectDTO.class))),
+	})
+	@Path("/me")
+	@GET
+	@Produces(MediaType.APPLICATION_JSON)
+	public Response getUserProjects(@Parameter(hidden = true) @Auth UserInfo userInfo) {
+		return Response
+				.ok(projectService.getUserProjects(userInfo))
+				.build();
+	}
+
+	@Operation(summary = "Update project", tags = "project")
+	@ApiResponses({
+			@ApiResponse(responseCode = "200", description = "Project is successfully updated"),
+			@ApiResponse(responseCode = "400", description = "Validation error", content = @Content(mediaType =
+					MediaType.APPLICATION_JSON,
+					schema = @Schema(implementation = ErrorDTO.class))),
+			@ApiResponse(responseCode = "404", description = "Project with passed name not found",
+					content = @Content(mediaType = MediaType.APPLICATION_JSON,
+							schema = @Schema(implementation = ErrorDTO.class)))
+	})
+	@PUT
+	public Response updateProject(@Parameter(hidden = true) @Auth UserInfo userInfo, UpdateProjectDTO projectDTO) {
+		projectService.update(projectDTO);
+		return Response.ok().build();
+	}
+
+	@Operation(summary = "Remove project", tags = "project")
+	@ApiResponses({
+			@ApiResponse(responseCode = "200", description = "Project is successfully removed"),
+			@ApiResponse(responseCode = "404", description = "Project with passed name not found",
+					content = @Content(mediaType = MediaType.APPLICATION_JSON,
+							schema = @Schema(implementation = ErrorDTO.class)))
+	})
+	@DELETE
+	@Path("{name}")
+	public Response removeProject(
+			@Parameter(hidden = true) @Auth UserInfo userInfo,
+			@Parameter(description = "Project name")
+			@PathParam("name") String name) {
+		projectService.terminate(userInfo, name);
+		return Response.ok().build();
+	}
+
+	@Operation(summary = "Updates project budget", tags = "project")
+	@ApiResponses({
+			@ApiResponse(responseCode = "200", description = "Project budget is successfully updated"),
+			@ApiResponse(responseCode = "404", description = "Project with specified name not found"),
+			@ApiResponse(responseCode = "400", description = "Validation error",
+					content = @Content(mediaType = MediaType.APPLICATION_JSON,
+							schema = @Schema(implementation = ErrorDTO.class)))
+	})
+	@PUT
+	@Path("/budget")
+	public Response updateBudget(
+			@Parameter(hidden = true) @Auth UserInfo userInfo,
+			@Parameter(description = "Project name")
+					UpdateProjectBudgetDTO dto) {
+		projectService.updateBudget(dto.getProject(), dto.getBudget());
+		return Response.ok().build();
+	}
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/aws/ComputationalResourceAws.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/aws/ComputationalResourceAws.java
index 6346082..222d0b9 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/aws/ComputationalResourceAws.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/aws/ComputationalResourceAws.java
@@ -105,7 +105,7 @@
 					.version(form.getVersion())
 					.build();
 			boolean resourceAdded = computationalService.createDataEngineService(userInfo, form,
-					awsComputationalResource);
+					awsComputationalResource, form.getProject());
 			return resourceAdded ? Response.ok().build() : Response.status(Response.Status.FOUND).build();
 		}
 
@@ -133,7 +133,7 @@
 		log.debug("Create computational resources for {} | form is {}", userInfo.getName(), form);
 
 		validate(form);
-		return computationalService.createSparkCluster(userInfo, form)
+		return computationalService.createSparkCluster(userInfo, form, form.getProject())
 				? Response.ok().build()
 				: Response.status(Response.Status.FOUND).build();
 	}
@@ -195,17 +195,19 @@
 	 * @return 200 OK if operation is successfully triggered
 	 */
 	@PUT
-	@Path("/{exploratoryName}/{computationalName}/start")
+	@Path("/{project}/{exploratoryName}/{computationalName}/start")
 	@ApiOperation("Starts Spark cluster on AWS")
 	@ApiResponses(@ApiResponse(code = 200, message = "Spark cluster on AWS successfully started"))
 	public Response start(@ApiParam(hidden = true) @Auth UserInfo userInfo,
 						  @ApiParam(value = "Notebook's name corresponding to Spark cluster", required = true)
 						  @PathParam("exploratoryName") String exploratoryName,
 						  @ApiParam(value = "Spark cluster's name for starting", required = true)
-						  @PathParam("computationalName") String computationalName) {
+						  @PathParam("computationalName") String computationalName,
+						  @ApiParam(value = "Project name", required = true)
+						  @PathParam("project") String project) {
 		log.debug("Starting computational resource {} for user {}", computationalName, userInfo.getName());
 
-		computationalService.startSparkCluster(userInfo, exploratoryName, computationalName);
+		computationalService.startSparkCluster(userInfo, exploratoryName, computationalName, project);
 
 		return Response.ok().build();
 	}
@@ -260,7 +262,7 @@
 	}
 
 	private void validate(UserInfo userInfo, AwsComputationalCreateForm formDTO) {
-		if (!UserRoles.checkAccess(userInfo, RoleType.COMPUTATIONAL, formDTO.getImage())) {
+		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 DlabException("You do not have the privileges to create a " + formDTO.getTemplateName());
 		}
@@ -277,16 +279,18 @@
 					".");
 		}
 
-		int slaveSpotInstanceBidPct = formDTO.getSlaveInstanceSpotPctPrice();
-		if (formDTO.getSlaveInstanceSpot() && (slaveSpotInstanceBidPct < configuration.getMinEmrSpotInstanceBidPct()
-				|| slaveSpotInstanceBidPct > configuration.getMaxEmrSpotInstanceBidPct())) {
-			log.debug("Creating computational resource {} for user {} fail: Spot instances bidding percentage value " +
-							"out of the boundaries. Minimum is {}, maximum is {}",
-					formDTO.getName(), userInfo.getName(), configuration.getMinEmrSpotInstanceBidPct(),
-					configuration.getMaxEmrSpotInstanceBidPct());
-			throw new DlabException("Spot instances bidding percentage value out of the boundaries. Minimum is " +
-					configuration.getMinEmrSpotInstanceBidPct() + ", maximum is " +
-					configuration.getMaxEmrSpotInstanceBidPct() + ".");
+		if (formDTO.getSlaveInstanceSpotPctPrice() != null){
+			int slaveSpotInstanceBidPct = formDTO.getSlaveInstanceSpotPctPrice();
+			if (formDTO.getSlaveInstanceSpot() && (slaveSpotInstanceBidPct < configuration.getMinEmrSpotInstanceBidPct()
+					|| slaveSpotInstanceBidPct > configuration.getMaxEmrSpotInstanceBidPct())) {
+				log.debug("Creating computational resource {} for user {} fail: Spot instances bidding percentage value " +
+								"out of the boundaries. Minimum is {}, maximum is {}",
+						formDTO.getName(), userInfo.getName(), configuration.getMinEmrSpotInstanceBidPct(),
+						configuration.getMaxEmrSpotInstanceBidPct());
+				throw new DlabException("Spot instances bidding percentage value out of the boundaries. Minimum is " +
+						configuration.getMinEmrSpotInstanceBidPct() + ", maximum is " +
+						configuration.getMaxEmrSpotInstanceBidPct() + ".");
+			}
 		}
 	}
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/azure/ComputationalResourceAzure.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/azure/ComputationalResourceAzure.java
index dcac05f..3441ada 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/azure/ComputationalResourceAzure.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/azure/ComputationalResourceAzure.java
@@ -95,12 +95,12 @@
 									 @Valid @NotNull SparkStandaloneClusterCreateForm form) {
 		log.debug("Create computational resources for {} | form is {}", userInfo.getName(), form);
 
-		if (!UserRoles.checkAccess(userInfo, RoleType.COMPUTATIONAL, form.getImage())) {
+		if (!UserRoles.checkAccess(userInfo, RoleType.COMPUTATIONAL, form.getImage(), userInfo.getRoles())) {
 			log.warn("Unauthorized attempt to create a {} by user {}", form.getImage(), userInfo.getName());
 			throw new DlabException("You do not have the privileges to create a " + form.getTemplateName());
 		}
 
-		return computationalService.createSparkCluster(userInfo, form)
+		return computationalService.createSparkCluster(userInfo, form, form.getProject())
 				? Response.ok().build()
 				: Response.status(Response.Status.FOUND).build();
 
@@ -165,17 +165,19 @@
 	 * @return 200 OK if operation is successfully triggered
 	 */
 	@PUT
-	@Path("/{exploratoryName}/{computationalName}/start")
+	@Path("/{project}/{exploratoryName}/{computationalName}/start")
 	@ApiOperation("Starts Spark cluster on Azure")
 	@ApiResponses(@ApiResponse(code = 200, message = "Spark cluster on Azure successfully started"))
 	public Response start(@ApiParam(hidden = true) @Auth UserInfo userInfo,
 						  @ApiParam(value = "Notebook's name corresponding to Spark cluster", required = true)
 						  @PathParam("exploratoryName") String exploratoryName,
 						  @ApiParam(value = "Spark cluster's name for starting", required = true)
-						  @PathParam("computationalName") String computationalName) {
+						  @PathParam("computationalName") String computationalName,
+						  @ApiParam(value = "Project name", required = true)
+						  @PathParam("project") String project) {
 		log.debug("Starting computational resource {} for user {}", computationalName, userInfo.getName());
 
-		computationalService.startSparkCluster(userInfo, exploratoryName, computationalName);
+		computationalService.startSparkCluster(userInfo, exploratoryName, computationalName, project);
 
 		return Response.ok().build();
 	}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/ProjectCallback.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/ProjectCallback.java
new file mode 100644
index 0000000..a1b0039
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/callback/ProjectCallback.java
@@ -0,0 +1,46 @@
+package com.epam.dlab.backendapi.resources.callback;
+
+import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.dao.ProjectDAO;
+import com.epam.dlab.backendapi.domain.ProjectDTO;
+import com.epam.dlab.backendapi.domain.RequestId;
+import com.epam.dlab.dto.UserInstanceStatus;
+import com.epam.dlab.dto.base.project.ProjectResult;
+import com.google.inject.Inject;
+import io.dropwizard.auth.Auth;
+import lombok.extern.slf4j.Slf4j;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+@Path("/project/status")
+@Consumes(MediaType.APPLICATION_JSON)
+@Slf4j
+public class ProjectCallback {
+
+	private final ProjectDAO projectDAO;
+	private final RequestId requestId;
+
+	@Inject
+	public ProjectCallback(ProjectDAO projectDAO, RequestId requestId) {
+		this.projectDAO = projectDAO;
+		this.requestId = requestId;
+	}
+
+
+	@POST
+	public Response updateProjectStatus(@Auth UserInfo userInfo, ProjectResult projectResult) {
+		requestId.checkAndRemove(projectResult.getRequestId());
+		final String projectName = projectResult.getProjectName();
+		final UserInstanceStatus status = UserInstanceStatus.of(projectResult.getStatus());
+		if (UserInstanceStatus.CREATED == status) {
+			projectDAO.updateEdgeInfoAndStatus(projectName, projectResult.getEdgeInfo(), ProjectDTO.Status.ACTIVE);
+		} else {
+			projectDAO.updateStatus(projectName, ProjectDTO.Status.from(status));
+		}
+		return Response.ok().build();
+	}
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ComputationalCreateFormDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ComputationalCreateFormDTO.java
index 98d51e6..ce619e4 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ComputationalCreateFormDTO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ComputationalCreateFormDTO.java
@@ -46,6 +46,12 @@
 	private String name;
 
 	@NotBlank
+	@JsonProperty
+	private String project;
+	@JsonProperty("custom_tag")
+	private String customTag;
+
+	@NotBlank
 	@JsonProperty("notebook_name")
 	private String notebookName;
 
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ExploratoryCreateFormDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ExploratoryCreateFormDTO.java
index c1dee78..e157b8b 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ExploratoryCreateFormDTO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ExploratoryCreateFormDTO.java
@@ -44,6 +44,16 @@
 
 	@NotBlank
 	@JsonProperty
+	private String project;
+	@JsonProperty("custom_tag")
+	private String exploratoryTag;
+
+	@NotBlank
+	@JsonProperty
+	private String endpoint;
+
+	@NotBlank
+	@JsonProperty
 	private String shape;
 
 	@NotBlank
@@ -144,6 +154,26 @@
 		return clusterConfig;
 	}
 
+	public String getProject() {
+		return project;
+	}
+
+	public void setProject(String project) {
+		this.project = project;
+	}
+
+	public String getEndpoint() {
+		return endpoint;
+	}
+
+	public void setEndpoint(String endpoint) {
+		this.endpoint = endpoint;
+	}
+
+	public String getExploratoryTag() {
+		return exploratoryTag;
+	}
+
 	@Override
 	public String toString() {
 		return MoreObjects.toStringHelper(this)
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusPageDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusPageDTO.java
index cdef1bb..b7f9362 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusPageDTO.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/HealthStatusPageDTO.java
@@ -40,6 +40,8 @@
 	private int billingQuoteUsed;
 	@JsonProperty
 	private int billingUserQuoteUsed;
+	@JsonProperty
+	private boolean projectAssigned;
 
 	/**
 	 * Return the status of environment.
@@ -83,6 +85,11 @@
 		return this;
 	}
 
+	public HealthStatusPageDTO withProjectAssinged(boolean isProjectAssigned) {
+		this.projectAssigned = isProjectAssigned;
+		return this;
+	}
+
 	/**
 	 * Return the list of resources.
 	 */
@@ -146,6 +153,10 @@
 		return admin;
 	}
 
+	public boolean isProjectAssigned() {
+		return projectAssigned;
+	}
+
 	public int getBillingQuoteUsed() {
 		return billingQuoteUsed;
 	}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ProjectActionFormDTO.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ProjectActionFormDTO.java
new file mode 100644
index 0000000..ac3a561
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/ProjectActionFormDTO.java
@@ -0,0 +1,10 @@
+package com.epam.dlab.backendapi.resources.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class ProjectActionFormDTO {
+	@JsonProperty("project_name")
+	private final String projectName;
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UserResourceInfo.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UserResourceInfo.java
index bf0e4d4..8b4eeb6 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UserResourceInfo.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/dto/UserResourceInfo.java
@@ -48,6 +48,8 @@
 
 	@JsonProperty
 	private String user;
+	@JsonProperty
+	private String project;
 
 	@JsonProperty("public_ip")
 	private String ip;
@@ -87,4 +89,9 @@
 		setIp(ip);
 		return this;
 	}
+
+	public UserResourceInfo withProject(String project) {
+		setProject(project);
+		return this;
+	}
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/ComputationalResourceGcp.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/ComputationalResourceGcp.java
index 87b7b02..f213e28 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/ComputationalResourceGcp.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/resources/gcp/ComputationalResourceGcp.java
@@ -100,7 +100,7 @@
 					.version(formDTO.getVersion())
 					.build();
 			boolean resourceAdded = computationalService.createDataEngineService(userInfo, formDTO,
-					gcpComputationalResource);
+					gcpComputationalResource, formDTO.getProject());
 			return resourceAdded ? Response.ok().build() : Response.status(Response.Status.FOUND).build();
 		}
 
@@ -127,12 +127,12 @@
 									 @Valid @NotNull SparkStandaloneClusterCreateForm form) {
 		log.debug("Create computational resources for {} | form is {}", userInfo.getName(), form);
 
-		if (!UserRoles.checkAccess(userInfo, RoleType.COMPUTATIONAL, form.getImage())) {
+		if (!UserRoles.checkAccess(userInfo, RoleType.COMPUTATIONAL, form.getImage(), userInfo.getRoles())) {
 			log.warn("Unauthorized attempt to create a {} by user {}", form.getImage(), userInfo.getName());
 			throw new DlabException("You do not have the privileges to create a " + form.getTemplateName());
 		}
 
-		return computationalService.createSparkCluster(userInfo, form)
+		return computationalService.createSparkCluster(userInfo, form, form.getProject())
 				? Response.ok().build()
 				: Response.status(Response.Status.FOUND).build();
 	}
@@ -196,17 +196,19 @@
 	 * @return 200 OK if operation is successfully triggered
 	 */
 	@PUT
-	@Path("/{exploratoryName}/{computationalName}/start")
+	@Path("/{project}/{exploratoryName}/{computationalName}/start")
 	@ApiOperation("Starts Spark cluster on GCP")
 	@ApiResponses(@ApiResponse(code = 200, message = "Spark cluster on GCP successfully started"))
 	public Response start(@ApiParam(hidden = true) @Auth UserInfo userInfo,
 						  @ApiParam(value = "Notebook's name corresponding to Spark cluster", required = true)
 						  @PathParam("exploratoryName") String exploratoryName,
 						  @ApiParam(value = "Spark cluster's name for starting", required = true)
-						  @PathParam("computationalName") String computationalName) {
+						  @PathParam("computationalName") String computationalName,
+						  @ApiParam(value = "Project name", required = true)
+						  @PathParam("project") String project) {
 		log.debug("Starting computational resource {} for user {}", computationalName, userInfo.getName());
 
-		computationalService.startSparkCluster(userInfo, exploratoryName, computationalName);
+		computationalService.startSparkCluster(userInfo, exploratoryName, computationalName, project);
 
 		return Response.ok().build();
 	}
@@ -246,7 +248,7 @@
 	}
 
 	private void validate(@Auth UserInfo userInfo, GcpComputationalCreateForm formDTO) {
-		if (!UserRoles.checkAccess(userInfo, RoleType.COMPUTATIONAL, formDTO.getImage())) {
+		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 DlabException("You do not have the privileges to create a " + formDTO.getTemplateName());
 		}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/roles/UserRoles.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/roles/UserRoles.java
index 032d232..a8800e2 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/roles/UserRoles.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/roles/UserRoles.java
@@ -88,28 +88,31 @@
 	 * @param userInfo user info.
 	 * @param type     the type of role.
 	 * @param name     the name of role.
+	 * @param roles
 	 * @return boolean value
 	 */
-	public static boolean checkAccess(UserInfo userInfo, RoleType type, String name) {
-		return checkAccess(userInfo, type, name, true);
+	public static boolean checkAccess(UserInfo userInfo, RoleType type, String name, Collection<String> roles) {
+		return checkAccess(userInfo, type, name, true, roles);
 	}
 
 	public static boolean isAdmin(UserInfo userInfo) {
 		final List<UserRole> roles = UserRoles.getRoles();
 		return roles == null || roles.stream().anyMatch(r -> ADMIN_ROLE_NAME.equals(r.getId()) &&
-				(userRoles.hasAccessByGroup(userInfo, r) || userRoles.hasAccessByUserName(userInfo, r)));
+				(userRoles.hasAccessByGroup(userInfo, r, userInfo.getRoles()) || userRoles.hasAccessByUserName(userInfo, r)));
 	}
 
 	/**
 	 * Check access for user to the role.
 	 *
+	 * @param roles
 	 * @param userInfo user info.
 	 * @param type     the type of role.
 	 * @param name     the name of role.
 	 * @return boolean value
 	 */
-	public static boolean checkAccess(UserInfo userInfo, RoleType type, String name, boolean useDefault) {
-		return (userRoles == null || userRoles.hasAccess(userInfo, type, name, useDefault));
+	public static boolean checkAccess(UserInfo userInfo, RoleType type, String name, boolean useDefault,
+									  Collection<String> roles) {
+		return (userRoles == null || userRoles.hasAccess(userInfo, type, name, useDefault, roles));
 	}
 
 	/**
@@ -216,9 +219,11 @@
 	 * @param type       the type of role.
 	 * @param name       the name of role.
 	 * @param useDefault true/false
+	 * @param roles
 	 * @return boolean value
 	 */
-	private boolean hasAccess(UserInfo userInfo, RoleType type, String name, boolean useDefault) {
+	private boolean hasAccess(UserInfo userInfo, RoleType type, String name, boolean useDefault,
+							  Collection<String> roles) {
 		if (userRoles == null) {
 			return true;
 		}
@@ -228,18 +233,18 @@
 		if (role == null) {
 			return checkDefault(useDefault);
 		}
-		if (hasAccessByGroup(userInfo, role)) return true;
+		if (hasAccessByGroup(userInfo, role, roles)) return true;
 		LOGGER.trace("Access denied for user {} to {}/{}", userInfo.getName(), type, name);
 		return false;
 	}
 
-	private boolean hasAccessByGroup(UserInfo userInfo, UserRole role) {
+	private boolean hasAccessByGroup(UserInfo userInfo, UserRole role, Collection<String> userRoles) {
 		Set<String> groups = role.getGroups();
 		if (groups != null) {
 			if (groups.contains(ANY_USER)) {
 				return true;
 			}
-			for (String group : userInfo.getRoles()) {
+			for (String group : userRoles) {
 				if (group != null && groups.contains(group.toLowerCase())) {
 					LOGGER.trace("Got access by group {}", group);
 					return true;
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/CheckProjectQuoteScheduler.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/CheckProjectQuoteScheduler.java
new file mode 100644
index 0000000..f253145
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/schedulers/CheckProjectQuoteScheduler.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.dlab.backendapi.schedulers;
+
+import com.epam.dlab.backendapi.dao.BillingDAO;
+import com.epam.dlab.backendapi.domain.ProjectDTO;
+import com.epam.dlab.backendapi.schedulers.internal.Scheduled;
+import com.epam.dlab.backendapi.service.EnvironmentService;
+import com.epam.dlab.backendapi.service.ProjectService;
+import com.google.inject.Inject;
+import lombok.extern.slf4j.Slf4j;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+
+@Scheduled("checkProjectQuoteScheduler")
+@Slf4j
+public class CheckProjectQuoteScheduler implements Job {
+
+	@Inject
+	private BillingDAO billingDAO;
+	@Inject
+	private EnvironmentService environmentService;
+	@Inject
+	private ProjectService projectService;
+
+	@Override
+	public void execute(JobExecutionContext context) {
+		projectService.getProjects()
+				.stream()
+				.map(ProjectDTO::getName)
+				.filter(billingDAO::isProjectQuoteReached)
+				.peek(p -> log.warn("Stopping {} project env because of reaching user billing quote", p))
+				.forEach(environmentService::stopProjectEnvironment);
+	}
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ComputationalService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ComputationalService.java
index 1be1be5..217e18e 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ComputationalService.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ComputationalService.java
@@ -40,7 +40,7 @@
 	 * name already exists
 	 * @throws IllegalArgumentException if input parameters exceed limits or docker image name is malformed
 	 */
-	boolean createSparkCluster(UserInfo userInfo, SparkStandaloneClusterCreateForm form);
+	boolean createSparkCluster(UserInfo userInfo, SparkStandaloneClusterCreateForm form, String project);
 
 	/**
 	 * Asynchronously triggers termination of computational resources
@@ -53,11 +53,11 @@
 	void terminateComputational(UserInfo userInfo, String exploratoryName, String computationalName);
 
 	boolean createDataEngineService(UserInfo userInfo, ComputationalCreateFormDTO formDTO, UserComputationalResource
-			computationalResource);
+			computationalResource, String project);
 
 	void stopSparkCluster(UserInfo userInfo, String exploratoryName, String computationalName);
 
-	void startSparkCluster(UserInfo userInfo, String exploratoryName, String computationalName);
+	void startSparkCluster(UserInfo userInfo, String exploratoryName, String computationalName, String project);
 
 	void updateSparkClusterConfig(UserInfo userInfo, String exploratoryName, String computationalName,
 								  List<ClusterConfig> config);
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/EndpointService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/EndpointService.java
new file mode 100644
index 0000000..fca6c5d
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/EndpointService.java
@@ -0,0 +1,14 @@
+package com.epam.dlab.backendapi.service;
+
+import com.epam.dlab.backendapi.domain.EndpointDTO;
+
+import java.util.List;
+
+public interface EndpointService {
+	List<EndpointDTO> getEndpoints();
+	EndpointDTO get(String name);
+
+	void create(EndpointDTO endpointDTO);
+
+	void remove(String name);
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/EnvironmentService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/EnvironmentService.java
index cb9371d..230e50e 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/EnvironmentService.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/EnvironmentService.java
@@ -36,6 +36,7 @@
 	void stopAll();
 
 	void stopEnvironment(String user);
+	void stopProjectEnvironment(String project);
 
 	void stopEdge(String user);
 
@@ -46,6 +47,7 @@
 	void terminateAll();
 
 	void terminateEnvironment(String user);
+	void terminateProjectEnvironment(String project);
 
 	void terminateExploratory(String user, String exploratoryName);
 
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ExploratoryService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ExploratoryService.java
index be83ca7..e3729aa 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ExploratoryService.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ExploratoryService.java
@@ -31,13 +31,13 @@
 
 public interface ExploratoryService {
 
-	String start(UserInfo userInfo, String exploratoryName);
+	String start(UserInfo userInfo, String exploratoryName, String project);
 
 	String stop(UserInfo userInfo, String exploratoryName);
 
 	String terminate(UserInfo userInfo, String exploratoryName);
 
-	String create(UserInfo userInfo, Exploratory exploratory);
+	String create(UserInfo userInfo, Exploratory exploratory, String project);
 
 	void updateExploratoryStatuses(String user, UserInstanceStatus status);
 
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/InfrastructureInfoService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/InfrastructureInfoService.java
index b54edb9..64e45be 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/InfrastructureInfoService.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/InfrastructureInfoService.java
@@ -19,6 +19,7 @@
 
 package com.epam.dlab.backendapi.service;
 
+import com.epam.dlab.auth.UserInfo;
 import com.epam.dlab.backendapi.resources.dto.HealthStatusPageDTO;
 import com.epam.dlab.backendapi.resources.dto.InfrastructureInfo;
 import com.epam.dlab.dto.InfrastructureMetaInfoDTO;
@@ -26,7 +27,7 @@
 public interface InfrastructureInfoService {
 	InfrastructureInfo getUserResources(String user);
 
-	HealthStatusPageDTO getHeathStatus(String user, boolean fullReport, boolean isAdmin);
+	HealthStatusPageDTO getHeathStatus(UserInfo user, boolean fullReport, boolean isAdmin);
 
 	InfrastructureMetaInfoDTO getInfrastructureMetaInfo();
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/InfrastructureTemplateService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/InfrastructureTemplateService.java
index 75d2b2b..4d6eba5 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/InfrastructureTemplateService.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/InfrastructureTemplateService.java
@@ -26,7 +26,7 @@
 import java.util.List;
 
 public interface InfrastructureTemplateService {
-	List<ExploratoryMetadataDTO> getExploratoryTemplates(UserInfo user);
+	List<ExploratoryMetadataDTO> getExploratoryTemplates(UserInfo user, String project);
 
-	List<FullComputationalTemplate> getComputationalTemplates(UserInfo user);
+	List<FullComputationalTemplate> getComputationalTemplates(UserInfo user, String project);
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ProjectService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ProjectService.java
new file mode 100644
index 0000000..27451bc
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/ProjectService.java
@@ -0,0 +1,31 @@
+package com.epam.dlab.backendapi.service;
+
+import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.domain.ProjectDTO;
+import com.epam.dlab.backendapi.domain.UpdateProjectDTO;
+
+import java.util.List;
+
+public interface ProjectService {
+	List<ProjectDTO> getProjects();
+
+	List<ProjectDTO> getUserProjects(UserInfo userInfo);
+
+	List<ProjectDTO> getProjectsWithStatus(ProjectDTO.Status status);
+
+	void create(UserInfo userInfo, ProjectDTO projectDTO);
+
+	ProjectDTO get(String name);
+
+	void terminate(UserInfo userInfo, String name);
+
+	void start(UserInfo userInfo, String name);
+
+	void stop(UserInfo userInfo, String name);
+
+	void update(UpdateProjectDTO projectDTO);
+
+	void updateBudget(String project, Integer budget);
+
+	boolean isAnyProjectAssigned(UserInfo userInfo);
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/TagService.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/TagService.java
new file mode 100644
index 0000000..f436f6d
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/TagService.java
@@ -0,0 +1,9 @@
+package com.epam.dlab.backendapi.service;
+
+import com.epam.dlab.auth.UserInfo;
+
+import java.util.Map;
+
+public interface TagService {
+	Map<String, String> getResourceTags(UserInfo userInfo, String endpoint, String project, String customTag);
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/TagServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/TagServiceImpl.java
new file mode 100644
index 0000000..c601815
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/TagServiceImpl.java
@@ -0,0 +1,40 @@
+package com.epam.dlab.backendapi.service;
+
+import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.dao.EndpointDAO;
+import com.epam.dlab.backendapi.dao.ProjectDAO;
+import com.epam.dlab.backendapi.domain.EndpointDTO;
+import com.epam.dlab.backendapi.domain.ProjectDTO;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Optional;
+
+@Singleton
+public class TagServiceImpl implements TagService {
+	private final EndpointDAO endpointDAO;
+	private final ProjectDAO projectDAO;
+
+	@Inject
+	public TagServiceImpl(EndpointDAO endpointDAO, ProjectDAO projectDAO) {
+		this.endpointDAO = endpointDAO;
+		this.projectDAO = projectDAO;
+	}
+
+	@Override
+	public Map<String, String> getResourceTags(UserInfo userInfo, String endpoint, String project,
+											   String customTag) {
+		Map<String, String> tags = new HashMap<>();
+		tags.put("user_tag", userInfo.getName());
+		endpointDAO.get(endpoint)
+				.map(EndpointDTO::getTag)
+				.ifPresent(tag -> tags.put("endpoint_tag", tag));
+			projectDAO.get(project)
+				.map(ProjectDTO::getTag)
+				.ifPresent(tag -> tags.put("project_tag", tag));
+		Optional.ofNullable(customTag).ifPresent(t -> tags.put("custom_tag", t));
+		return tags;
+	}
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImpl.java
index 70f68f4..1fe97d5 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImpl.java
@@ -22,12 +22,14 @@
 
 import com.epam.dlab.auth.UserInfo;
 import com.epam.dlab.backendapi.annotation.BudgetLimited;
+import com.epam.dlab.backendapi.annotation.Project;
 import com.epam.dlab.backendapi.dao.ComputationalDAO;
 import com.epam.dlab.backendapi.dao.ExploratoryDAO;
 import com.epam.dlab.backendapi.domain.RequestId;
 import com.epam.dlab.backendapi.resources.dto.ComputationalCreateFormDTO;
 import com.epam.dlab.backendapi.resources.dto.SparkStandaloneClusterCreateForm;
 import com.epam.dlab.backendapi.service.ComputationalService;
+import com.epam.dlab.backendapi.service.TagService;
 import com.epam.dlab.backendapi.util.RequestBuilder;
 import com.epam.dlab.constants.ServiceConsts;
 import com.epam.dlab.dto.UserInstanceDTO;
@@ -47,6 +49,7 @@
 
 import java.util.EnumMap;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 
 import static com.epam.dlab.dto.UserInstanceStatus.*;
@@ -80,25 +83,27 @@
 	@Inject
 	@Named(ServiceConsts.PROVISIONING_SERVICE_NAME)
 	private RESTService provisioningService;
-
 	@Inject
 	private RequestBuilder requestBuilder;
-
 	@Inject
 	private RequestId requestId;
+	@Inject
+	private TagService tagService;
 
 
 	@BudgetLimited
 	@Override
-	public boolean createSparkCluster(UserInfo userInfo, SparkStandaloneClusterCreateForm form) {
+	public boolean createSparkCluster(UserInfo userInfo, SparkStandaloneClusterCreateForm form,
+									  @Project String project) {
 
-		if (computationalDAO.addComputational(userInfo.getName(), form.getNotebookName(),
-				createInitialComputationalResource(form))) {
 
+		final UserInstanceDTO instance =
+				exploratoryDAO.fetchExploratoryFields(userInfo.getName(), form.getNotebookName());
+		final SparkStandaloneClusterResource compResource = createInitialComputationalResource(form);
+		compResource.setTags(tagService.getResourceTags(userInfo, instance.getEndpoint(), project,
+				form.getCustomTag()));
+		if (computationalDAO.addComputational(userInfo.getName(), form.getNotebookName(), compResource)) {
 			try {
-				UserInstanceDTO instance =
-						exploratoryDAO.fetchExploratoryFields(userInfo.getName(), form.getNotebookName());
-
 				ComputationalBase<?> dto = requestBuilder.newComputationalCreate(userInfo, instance, form);
 
 				String uuid = provisioningService.post(ComputationalAPI.COMPUTATIONAL_CREATE_SPARK,
@@ -126,13 +131,15 @@
 
 			updateComputationalStatus(userInfo.getName(), exploratoryName, computationalName, TERMINATING);
 
-			String exploratoryId = exploratoryDAO.fetchExploratoryId(userInfo.getName(), exploratoryName);
+			final UserInstanceDTO userInstanceDTO = exploratoryDAO.fetchExploratoryFields(userInfo.getName(),
+					exploratoryName);
 			UserComputationalResource compResource = computationalDAO.fetchComputationalFields(userInfo
 					.getName(), exploratoryName, computationalName);
 
 			final DataEngineType dataEngineType = compResource.getDataEngineType();
 			ComputationalTerminateDTO dto = requestBuilder.newComputationalTerminate(userInfo, exploratoryName,
-					exploratoryId, computationalName, compResource.getComputationalId(), dataEngineType);
+					userInstanceDTO.getExploratoryId(), computationalName, compResource.getComputationalId(),
+					dataEngineType, userInstanceDTO.getProject());
 
 			final String provisioningUrl = Optional.ofNullable(DATA_ENGINE_TYPE_TERMINATE_URLS.get(dataEngineType))
 					.orElseThrow(UnsupportedOperationException::new);
@@ -153,15 +160,18 @@
 	@BudgetLimited
 	@Override
 	public boolean createDataEngineService(UserInfo userInfo, ComputationalCreateFormDTO formDTO,
-										   UserComputationalResource computationalResource) {
+										   UserComputationalResource computationalResource, @Project String project) {
 
+		final UserInstanceDTO instance = exploratoryDAO.fetchExploratoryFields(userInfo.getName(), formDTO
+				.getNotebookName());
+		final Map<String, String> tags = tagService.getResourceTags(userInfo, instance.getEndpoint(), project,
+				formDTO.getCustomTag());
+		computationalResource.setTags(tags);
 		boolean isAdded = computationalDAO.addComputational(userInfo.getName(), formDTO.getNotebookName(),
 				computationalResource);
 
 		if (isAdded) {
 			try {
-				UserInstanceDTO instance = exploratoryDAO.fetchExploratoryFields(userInfo.getName(), formDTO
-						.getNotebookName());
 				String uuid = provisioningService.post(COMPUTATIONAL_CREATE_CLOUD_SPECIFIC, userInfo.getAccessToken(),
 						requestBuilder.newComputationalCreate(userInfo, instance, formDTO), String.class);
 				requestId.put(userInfo.getName(), uuid);
@@ -202,7 +212,7 @@
 
 	@BudgetLimited
 	@Override
-	public void startSparkCluster(UserInfo userInfo, String expName, String compName) {
+	public void startSparkCluster(UserInfo userInfo, String expName, String compName, @Project String project) {
 		final UserInstanceDTO userInstance =
 				exploratoryDAO.fetchExploratoryFields(userInfo.getName(), expName, true);
 		final UserInstanceStatus requiredStatus = UserInstanceStatus.STOPPED;
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/EndpointServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/EndpointServiceImpl.java
new file mode 100644
index 0000000..47377cd
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/EndpointServiceImpl.java
@@ -0,0 +1,44 @@
+package com.epam.dlab.backendapi.service.impl;
+
+import com.epam.dlab.backendapi.dao.EndpointDAO;
+import com.epam.dlab.backendapi.domain.EndpointDTO;
+import com.epam.dlab.backendapi.service.EndpointService;
+import com.epam.dlab.exceptions.ResourceConflictException;
+import com.epam.dlab.exceptions.ResourceNotFoundException;
+import com.google.inject.Inject;
+
+import java.util.List;
+
+public class EndpointServiceImpl implements EndpointService {
+	private final EndpointDAO endpointDAO;
+
+	@Inject
+	public EndpointServiceImpl(EndpointDAO endpointDAO) {
+		this.endpointDAO = endpointDAO;
+	}
+
+	@Override
+	public List<EndpointDTO> getEndpoints() {
+		return endpointDAO.getEndpoints();
+	}
+
+	@Override
+	public EndpointDTO get(String name) {
+		return endpointDAO.get(name)
+				.orElseThrow(() -> new ResourceNotFoundException("Endpoint with name " + name + " not found"));
+	}
+
+	@Override
+	public void create(EndpointDTO endpointDTO) {
+		if (!endpointDAO.get(endpointDTO.getName()).isPresent()) {
+			endpointDAO.create(endpointDTO);
+		} else {
+			throw new ResourceConflictException("Project with passed name already exist in system");
+		}
+	}
+
+	@Override
+	public void remove(String name) {
+		endpointDAO.remove(name);
+	}
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImpl.java
index ade44fb..1a68cd1 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImpl.java
@@ -25,15 +25,12 @@
 import com.epam.dlab.backendapi.dao.ExploratoryDAO;
 import com.epam.dlab.backendapi.dao.KeyDAO;
 import com.epam.dlab.backendapi.dao.UserSettingsDAO;
+import com.epam.dlab.backendapi.domain.ProjectDTO;
 import com.epam.dlab.backendapi.resources.dto.UserDTO;
 import com.epam.dlab.backendapi.resources.dto.UserResourceInfo;
-import com.epam.dlab.backendapi.service.ComputationalService;
-import com.epam.dlab.backendapi.service.EdgeService;
-import com.epam.dlab.backendapi.service.EnvironmentService;
-import com.epam.dlab.backendapi.service.ExploratoryService;
+import com.epam.dlab.backendapi.service.*;
 import com.epam.dlab.dto.UserInstanceDTO;
 import com.epam.dlab.dto.UserInstanceStatus;
-import com.epam.dlab.dto.base.edge.EdgeInfo;
 import com.epam.dlab.exceptions.ResourceConflictException;
 import com.epam.dlab.model.ResourceEnum;
 import com.google.inject.Inject;
@@ -71,6 +68,8 @@
 	@Inject
 	private EdgeService edgeService;
 	@Inject
+	private ProjectService projectService;
+	@Inject
 	private UserSettingsDAO settingsDAO;
 
 	@Override
@@ -99,7 +98,9 @@
 	public List<UserResourceInfo> getAllEnv() {
 		log.debug("Getting all user's environment...");
 		List<UserInstanceDTO> expList = exploratoryDAO.getInstances();
-		return getUserNames().stream().map(user -> getUserEnv(user, expList)).flatMap(Collection::stream)
+		return projectService.getProjectsWithStatus(ProjectDTO.Status.ACTIVE)
+				.stream()
+				.map(projectDTO -> getProjectEnv(projectDTO, expList)).flatMap(Collection::stream)
 				.collect(toList());
 	}
 
@@ -119,6 +120,14 @@
 	}
 
 	@Override
+	public void stopProjectEnvironment(String project) {
+		log.debug("Stopping environment for project {}", project);
+		checkProjectResourceConditions(project, "stop");
+		exploratoryDAO.fetchRunningExploratoryFieldsForProject(project)
+				.forEach(this::stopNotebook);
+	}
+
+	@Override
 	public void stopEdge(String user) {
 		if (UserInstanceStatus.RUNNING.toString().equals(keyDAO.getEdgeStatus(user))) {
 			edgeService.stop(systemUserInfoService.create(user));
@@ -153,6 +162,15 @@
 	}
 
 	@Override
+	public void terminateProjectEnvironment(String project) {
+		log.debug("Terminating environment for project {}", project);
+		checkProjectResourceConditions(project, "terminate");
+		exploratoryDAO.fetchProjectExploratoriesWhereStatusNotIn(project, UserInstanceStatus.TERMINATED,
+				UserInstanceStatus.FAILED, UserInstanceStatus.TERMINATING)
+				.forEach(this::terminateNotebook);
+	}
+
+	@Override
 	public void terminateExploratory(String user, String exploratoryName) {
 		terminateNotebook(new UserInstanceDTO().withUser(user).withExploratoryName(exploratoryName));
 	}
@@ -208,14 +226,13 @@
 		computationalService.terminateComputational(userInfo, exploratoryName, computationalName);
 	}
 
-	private List<UserResourceInfo> getUserEnv(String user, List<UserInstanceDTO> allInstances) {
-		EdgeInfo edgeInfo = keyDAO.getEdgeInfo(user);
+	private List<UserResourceInfo> getProjectEnv(ProjectDTO projectDTO, List<UserInstanceDTO> allInstances) {
 		UserResourceInfo edgeResource = new UserResourceInfo().withResourceType(ResourceEnum.EDGE_NODE)
-				.withResourceStatus(edgeInfo.getEdgeStatus())
-				.withUser(user)
-				.withIp(edgeInfo.getPublicIp());
+				.withResourceStatus("running")
+				.withProject(projectDTO.getName())
+				.withIp(projectDTO.getEdgeInfo().getPublicIp());
 		return Stream.concat(Stream.of(edgeResource), allInstances.stream()
-				.filter(instance -> instance.getUser().equals(user)).map(this::toUserResourceInfo))
+				.filter(instance -> instance.getProject().equals(projectDTO.getName())).map(this::toUserResourceInfo))
 				.collect(toList());
 	}
 
@@ -225,6 +242,19 @@
 				.withResourceShape(userInstance.getShape())
 				.withResourceStatus(userInstance.getStatus())
 				.withCompResources(userInstance.getResources())
-				.withUser(userInstance.getUser());
+				.withUser(userInstance.getUser())
+				.withProject(userInstance.getProject());
+	}
+
+	private void checkProjectResourceConditions(String project, String action) {
+		final List<UserInstanceDTO> userInstances = exploratoryDAO
+				.fetchProjectExploratoriesWhereStatusIn(project,
+						Arrays.asList(UserInstanceStatus.CREATING, UserInstanceStatus.STARTING,
+								UserInstanceStatus.CREATING_IMAGE),
+						UserInstanceStatus.CREATING, UserInstanceStatus.STARTING, UserInstanceStatus.CREATING_IMAGE);
+		if (!userInstances.isEmpty()) {
+			log.error(String.format(ERROR_MSG_FORMAT, action));
+			throw new ResourceConflictException(String.format(ERROR_MSG_FORMAT, action));
+		}
 	}
 }
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImpl.java
index 58f4aa5..9ce4a48 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImpl.java
@@ -21,12 +21,14 @@
 
 import com.epam.dlab.auth.UserInfo;
 import com.epam.dlab.backendapi.annotation.BudgetLimited;
+import com.epam.dlab.backendapi.annotation.Project;
 import com.epam.dlab.backendapi.dao.ComputationalDAO;
 import com.epam.dlab.backendapi.dao.ExploratoryDAO;
 import com.epam.dlab.backendapi.dao.GitCredsDAO;
 import com.epam.dlab.backendapi.dao.ImageExploratoryDao;
 import com.epam.dlab.backendapi.domain.RequestId;
 import com.epam.dlab.backendapi.service.ExploratoryService;
+import com.epam.dlab.backendapi.service.TagService;
 import com.epam.dlab.backendapi.util.RequestBuilder;
 import com.epam.dlab.constants.ServiceConsts;
 import com.epam.dlab.dto.StatusEnvBaseDTO;
@@ -72,10 +74,12 @@
 	private RequestBuilder requestBuilder;
 	@Inject
 	private RequestId requestId;
+	@Inject
+	private TagService tagService;
 
 	@BudgetLimited
 	@Override
-	public String start(UserInfo userInfo, String exploratoryName) {
+	public String start(UserInfo userInfo, String exploratoryName, @Project String project) {
 		return action(userInfo, exploratoryName, EXPLORATORY_START, STARTING);
 	}
 
@@ -91,15 +95,17 @@
 
 	@BudgetLimited
 	@Override
-	public String create(UserInfo userInfo, Exploratory exploratory) {
+	public String create(UserInfo userInfo, Exploratory exploratory, @Project String project) {
 		boolean isAdded = false;
 		try {
-			exploratoryDAO.insertExploratory(getUserInstanceDTO(userInfo, exploratory));
+			final UserInstanceDTO userInstanceDTO = getUserInstanceDTO(userInfo, exploratory, project);
+			exploratoryDAO.insertExploratory(userInstanceDTO);
 			isAdded = true;
 			final ExploratoryGitCredsDTO gitCreds = gitCredsDAO.findGitCreds(userInfo.getName());
 			log.debug("Created exploratory environment {} for user {}", exploratory.getName(), userInfo.getName());
-			final String uuid = provisioningService.post(EXPLORATORY_CREATE, userInfo.getAccessToken(),
-					requestBuilder.newExploratoryCreate(exploratory, userInfo, gitCreds), String.class);
+				final String uuid = provisioningService.post(EXPLORATORY_CREATE, userInfo.getAccessToken(),
+					requestBuilder.newExploratoryCreate(exploratory, userInfo, gitCreds, userInstanceDTO.getTags()),
+					String.class);
 			requestId.put(userInfo.getName(), uuid);
 			return uuid;
 		} catch (Exception t) {
@@ -309,7 +315,7 @@
 				.withStatus(status);
 	}
 
-	private UserInstanceDTO getUserInstanceDTO(UserInfo userInfo, Exploratory exploratory) {
+	private UserInstanceDTO getUserInstanceDTO(UserInfo userInfo, Exploratory exploratory, String project) {
 		final UserInstanceDTO userInstance = new UserInstanceDTO()
 				.withUser(userInfo.getName())
 				.withExploratoryName(exploratory.getName())
@@ -318,7 +324,11 @@
 				.withImageVersion(exploratory.getVersion())
 				.withTemplateName(exploratory.getTemplateName())
 				.withClusterConfig(exploratory.getClusterConfig())
-				.withShape(exploratory.getShape());
+				.withShape(exploratory.getShape())
+				.withProject(project)
+				.withEndpoint(exploratory.getEndpoint())
+				.withTags(tagService.getResourceTags(userInfo, exploratory.getEndpoint(), project,
+						exploratory.getExploratoryTag()));
 		if (StringUtils.isNotBlank(exploratory.getImageName())) {
 			final List<LibInstallDTO> libInstallDtoList = getImageRelatedLibraries(userInfo, exploratory
 					.getImageName());
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceBase.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceBase.java
index a5d1465..3ba548e 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceBase.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceBase.java
@@ -19,6 +19,7 @@
 
 package com.epam.dlab.backendapi.service.impl;
 
+import com.epam.dlab.auth.UserInfo;
 import com.epam.dlab.backendapi.SelfServiceApplicationConfiguration;
 import com.epam.dlab.backendapi.dao.BillingDAO;
 import com.epam.dlab.backendapi.dao.EnvDAO;
@@ -27,11 +28,11 @@
 import com.epam.dlab.backendapi.resources.dto.HealthStatusPageDTO;
 import com.epam.dlab.backendapi.resources.dto.InfrastructureInfo;
 import com.epam.dlab.backendapi.service.InfrastructureInfoService;
+import com.epam.dlab.backendapi.service.ProjectService;
 import com.epam.dlab.dto.InfrastructureMetaInfoDTO;
 import com.epam.dlab.dto.base.edge.EdgeInfo;
 import com.epam.dlab.exceptions.DlabException;
 import com.google.inject.Inject;
-import com.jcabi.manifests.Manifests;
 import lombok.extern.slf4j.Slf4j;
 import org.bson.Document;
 
@@ -52,6 +53,8 @@
 	private SelfServiceApplicationConfiguration configuration;
 	@Inject
 	private BillingDAO billingDAO;
+	@Inject
+	private ProjectService projectService;
 
 
 	@SuppressWarnings("unchecked")
@@ -73,12 +76,15 @@
 	}
 
 	@Override
-	public HealthStatusPageDTO getHeathStatus(String user, boolean fullReport, boolean isAdmin) {
+	public HealthStatusPageDTO getHeathStatus(UserInfo userInfo, boolean fullReport, boolean isAdmin) {
+		final String user = userInfo.getName();
 		log.debug("Request the status of resources for user {}, report type {}", user, fullReport);
 		try {
+
 			return envDAO.getHealthStatusPageDTO(user, fullReport)
 					.withBillingEnabled(configuration.isBillingSchedulerEnabled())
 					.withAdmin(isAdmin)
+					.withProjectAssinged(projectService.isAnyProjectAssigned(userInfo))
 					.withBillingQuoteUsed(billingDAO.getBillingQuoteUsed())
 					.withBillingUserQuoteUsed(billingDAO.getBillingUserQuoteUsed(user));
 		} catch (Exception e) {
@@ -89,13 +95,14 @@
 
 	@Override
 	public InfrastructureMetaInfoDTO getInfrastructureMetaInfo() {
-		final String branch = Manifests.read("GIT-Branch");
+		/*final String branch = Manifests.read("GIT-Branch");
 		return InfrastructureMetaInfoDTO.builder()
 				.branch(branch)
 				.commit(Manifests.read("GIT-Commit"))
 				.version(Manifests.read("DLab-Version"))
 				.releaseNotes(String.format(RELEASE_NOTES_FORMAT, branch))
-				.build();
+				.build();*/
+		return InfrastructureMetaInfoDTO.builder().build();
 	}
 
 	protected abstract Map<String, String> getSharedInfo(T sharedInfo);
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceBase.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceBase.java
index 4193fc6..e597d94 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceBase.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceBase.java
@@ -21,7 +21,9 @@
 
 import com.epam.dlab.auth.UserInfo;
 import com.epam.dlab.backendapi.SelfServiceApplicationConfiguration;
+import com.epam.dlab.backendapi.dao.ProjectDAO;
 import com.epam.dlab.backendapi.dao.SettingsDAO;
+import com.epam.dlab.backendapi.domain.ProjectDTO;
 import com.epam.dlab.backendapi.resources.dto.SparkStandaloneConfiguration;
 import com.epam.dlab.backendapi.roles.RoleType;
 import com.epam.dlab.backendapi.roles.UserRoles;
@@ -43,6 +45,7 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.stream.Collectors;
 
 import static com.epam.dlab.rest.contracts.DockerAPI.DOCKER_COMPUTATIONAL;
@@ -56,6 +59,8 @@
 
 	@Inject
 	private SettingsDAO settingsDAO;
+	@Inject
+	private ProjectDAO projectDAO;
 
 
 	@Inject
@@ -63,18 +68,20 @@
 	private RESTService provisioningService;
 
 	@Override
-	public List<ExploratoryMetadataDTO> getExploratoryTemplates(UserInfo user) {
+	public List<ExploratoryMetadataDTO> getExploratoryTemplates(UserInfo user, String project) {
 
-		log.debug("Loading list of exploratory templates for user {}", user.getName());
+		log.debug("Loading list of exploratory templates for user {} for project {}", user.getName(), project);
 		try {
 			ExploratoryMetadataDTO[] array =
 					provisioningService.get(DOCKER_EXPLORATORY, user.getAccessToken(), ExploratoryMetadataDTO[].class);
 
+			final Set<String> roles = getRoles(user, project);
 			return Arrays.stream(array)
 					.peek(e -> e.setImage(getSimpleImageName(e.getImage())))
 					.filter(e -> exploratoryGpuIssuesAzureFilter(e) &&
-							UserRoles.checkAccess(user, RoleType.EXPLORATORY, e.getImage()))
-					.peek(e -> filterShapes(user, e.getExploratoryEnvironmentShapes(), RoleType.EXPLORATORY_SHAPES))
+							UserRoles.checkAccess(user, RoleType.EXPLORATORY, e.getImage(), roles))
+					.peek(e -> filterShapes(user, e.getExploratoryEnvironmentShapes(), RoleType.EXPLORATORY_SHAPES,
+							roles))
 					.collect(Collectors.toList());
 
 		} catch (DlabException e) {
@@ -89,15 +96,16 @@
 	 * @param user              user
 	 * @param environmentShapes shape types
 	 * @param roleType
+	 * @param roles
 	 */
 	private void filterShapes(UserInfo user, Map<String, List<ComputationalResourceShapeDto>> environmentShapes,
-							  RoleType roleType) {
+							  RoleType roleType, Set<String> roles) {
 		environmentShapes.forEach((k, v) -> v.removeIf(compResShapeDto ->
-				!UserRoles.checkAccess(user, roleType, compResShapeDto.getType())));
+				!UserRoles.checkAccess(user, roleType, compResShapeDto.getType(), roles)));
 	}
 
 	@Override
-	public List<FullComputationalTemplate> getComputationalTemplates(UserInfo user) {
+	public List<FullComputationalTemplate> getComputationalTemplates(UserInfo user, String project) {
 
 		log.debug("Loading list of computational templates for user {}", user.getName());
 		try {
@@ -105,10 +113,13 @@
 					provisioningService.get(DOCKER_COMPUTATIONAL, user.getAccessToken(), ComputationalMetadataDTO[]
 							.class);
 
+			final Set<String> roles = getRoles(user, project);
+
 			return Arrays.stream(array)
 					.peek(e -> e.setImage(getSimpleImageName(e.getImage())))
-					.peek(e -> filterShapes(user, e.getComputationResourceShapes(), RoleType.COMPUTATIONAL_SHAPES))
-					.filter(e -> UserRoles.checkAccess(user, RoleType.COMPUTATIONAL, e.getImage()))
+					.peek(e -> filterShapes(user, e.getComputationResourceShapes(), RoleType.COMPUTATIONAL_SHAPES,
+							user.getRoles()))
+					.filter(e -> UserRoles.checkAccess(user, RoleType.COMPUTATIONAL, e.getImage(), roles))
 					.map(this::fullComputationalTemplate)
 					.collect(Collectors.toList());
 
@@ -118,6 +129,12 @@
 		}
 	}
 
+	private Set<String> getRoles(UserInfo user, String project) {
+		return projectDAO.get(project)
+				.map(ProjectDTO::getGroups)
+				.orElse(user.getRoles());
+	}
+
 	protected abstract FullComputationalTemplate getCloudFullComputationalTemplate(ComputationalMetadataDTO
 																						   metadataDTO);
 
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java
new file mode 100644
index 0000000..c43b9a4
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/ProjectServiceImpl.java
@@ -0,0 +1,153 @@
+package com.epam.dlab.backendapi.service.impl;
+
+import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.dao.ProjectDAO;
+import com.epam.dlab.backendapi.dao.UserGroupDao;
+import com.epam.dlab.backendapi.domain.ProjectDTO;
+import com.epam.dlab.backendapi.domain.RequestId;
+import com.epam.dlab.backendapi.domain.UpdateProjectDTO;
+import com.epam.dlab.backendapi.service.EnvironmentService;
+import com.epam.dlab.backendapi.service.ProjectService;
+import com.epam.dlab.constants.ServiceConsts;
+import com.epam.dlab.dto.project.ProjectActionDTO;
+import com.epam.dlab.dto.project.ProjectCreateDTO;
+import com.epam.dlab.exceptions.ResourceConflictException;
+import com.epam.dlab.exceptions.ResourceNotFoundException;
+import com.epam.dlab.rest.client.RESTService;
+import com.google.inject.Inject;
+import com.google.inject.name.Named;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.List;
+import java.util.Set;
+import java.util.function.Supplier;
+
+import static java.util.stream.Collectors.toSet;
+import static java.util.stream.Stream.concat;
+
+@Slf4j
+public class ProjectServiceImpl implements ProjectService {
+
+	private static final String CREATE_PRJ_API = "infrastructure/project/create";
+	private static final String TERMINATE_PRJ_API = "infrastructure/project/terminate";
+	private static final String START_PRJ_API = "infrastructure/project/start";
+	private static final String STOP_PRJ_API = "infrastructure/project/stop";
+	private final ProjectDAO projectDAO;
+	private final EnvironmentService environmentService;
+	private final UserGroupDao userGroupDao;
+	private final RESTService provisioningService;
+	private final RequestId requestId;
+
+	@Inject
+	public ProjectServiceImpl(ProjectDAO projectDAO, EnvironmentService environmentService,
+							  UserGroupDao userGroupDao,
+							  @Named(ServiceConsts.PROVISIONING_SERVICE_NAME) RESTService provisioningService,
+							  RequestId requestId) {
+		this.projectDAO = projectDAO;
+		this.environmentService = environmentService;
+		this.userGroupDao = userGroupDao;
+		this.provisioningService = provisioningService;
+		this.requestId = requestId;
+	}
+
+	@Override
+	public List<ProjectDTO> getProjects() {
+		return projectDAO.getProjects();
+	}
+
+	@Override
+	public List<ProjectDTO> getUserProjects(UserInfo userInfo) {
+		return projectDAO.getUserProjectsWithStatus(userInfo, ProjectDTO.Status.ACTIVE);
+	}
+
+	@Override
+	public List<ProjectDTO> getProjectsWithStatus(ProjectDTO.Status status) {
+		return projectDAO.getProjectsWithStatus(status);
+	}
+
+	@Override
+	public void create(UserInfo user, ProjectDTO projectDTO) {
+		if (!projectDAO.get(projectDTO.getName()).isPresent()) {
+			projectDAO.create(projectDTO);
+			createProjectOnCloud(user, projectDTO);
+		} else {
+			throw new ResourceConflictException("Project with passed name already exist in system");
+		}
+	}
+
+	@Override
+	public ProjectDTO get(String name) {
+		return projectDAO.get(name)
+				.orElseThrow(projectNotFound());
+	}
+
+	@Override
+	public void terminate(UserInfo userInfo, String name) {
+		projectActionOnCloud(userInfo, name, TERMINATE_PRJ_API);
+		environmentService.terminateProjectEnvironment(name);
+		projectDAO.updateStatus(name, ProjectDTO.Status.DELETING);
+	}
+
+	@Override
+	public void start(UserInfo userInfo, String name) {
+		projectActionOnCloud(userInfo, name, START_PRJ_API);
+		projectDAO.updateStatus(name, ProjectDTO.Status.ACTIVATING);
+	}
+
+	@Override
+	public void stop(UserInfo userInfo, String name) {
+		projectActionOnCloud(userInfo, name, STOP_PRJ_API);
+		projectDAO.updateStatus(name, ProjectDTO.Status.DEACTIVATING);
+	}
+
+	@Override
+	public void update(UpdateProjectDTO projectDTO) {
+		if (!projectDAO.update(projectDTO)) {
+			throw projectNotFound().get();
+		}
+	}
+
+	@Override
+	public void updateBudget(String project, Integer budget) {
+		projectDAO.updateBudget(project, budget);
+	}
+
+	@Override
+	public boolean isAnyProjectAssigned(UserInfo userInfo) {
+		final Set<String> userGroups = concat(userInfo.getRoles().stream(),
+				userGroupDao.getUserGroups(userInfo.getName()).stream())
+				.collect(toSet());
+		return projectDAO.isAnyProjectAssigned(userGroups);
+	}
+
+	private void createProjectOnCloud(UserInfo user, ProjectDTO projectDTO) {
+		try {
+			final ProjectCreateDTO projectDto = ProjectCreateDTO.builder()
+					.key(projectDTO.getKey())
+					.name(projectDTO.getName())
+					.tag(projectDTO.getTag())
+					.build();
+			String uuid = provisioningService.post(CREATE_PRJ_API, user.getAccessToken(), projectDto, String.class);
+			requestId.put(user.getName(), uuid);
+		} catch (Exception e) {
+			log.error("Can not create project due to: {}", e.getMessage());
+			projectDAO.updateStatus(projectDTO.getName(), ProjectDTO.Status.FAILED);
+		}
+	}
+
+
+	private void projectActionOnCloud(UserInfo user, String projectName, String provisioningApiUri) {
+		try {
+			String uuid = provisioningService.post(provisioningApiUri, user.getAccessToken(),
+					new ProjectActionDTO(projectName), String.class);
+			requestId.put(user.getName(), uuid);
+		} catch (Exception e) {
+			log.error("Can not terminate project due to: {}", e.getMessage());
+			projectDAO.updateStatus(projectName, ProjectDTO.Status.FAILED);
+		}
+	}
+
+	private Supplier<ResourceNotFoundException> projectNotFound() {
+		return () -> new ResourceNotFoundException("Project with passed name not found");
+	}
+}
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/SchedulerJobServiceImpl.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/SchedulerJobServiceImpl.java
index c906712..ebe9bcd 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/SchedulerJobServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/service/impl/SchedulerJobServiceImpl.java
@@ -243,7 +243,7 @@
 		final String user = schedulerJobData.getUser();
 		final String exploratoryName = schedulerJobData.getExploratoryName();
 		log.debug("Starting exploratory {} for user {} by scheduler", exploratoryName, user);
-		exploratoryService.start(systemUserService.create(user), exploratoryName);
+		exploratoryService.start(systemUserService.create(user), exploratoryName, "");
 		if (schedulerJobData.getJobDTO().isSyncStartRequired()) {
 			log.trace("Starting computational for exploratory {} for user {} by scheduler", exploratoryName, user);
 			final DataEngineType sparkCluster = DataEngineType.SPARK_STANDALONE;
@@ -266,7 +266,7 @@
 
 	private void startSpark(String user, String expName, String compName) {
 		log.debug("Starting exploratory {} computational {} for user {} by scheduler", expName, compName, user);
-		computationalService.startSparkCluster(systemUserService.create(user), expName, compName);
+		computationalService.startSparkCluster(systemUserService.create(user), expName, compName,"");
 	}
 
 	private boolean shouldClusterBeStarted(DataEngineType sparkCluster, UserComputationalResource compResource) {
diff --git a/services/self-service/src/main/java/com/epam/dlab/backendapi/util/RequestBuilder.java b/services/self-service/src/main/java/com/epam/dlab/backendapi/util/RequestBuilder.java
index b120c53..cd88930 100644
--- a/services/self-service/src/main/java/com/epam/dlab/backendapi/util/RequestBuilder.java
+++ b/services/self-service/src/main/java/com/epam/dlab/backendapi/util/RequestBuilder.java
@@ -68,6 +68,7 @@
 import com.google.inject.Singleton;
 
 import java.util.List;
+import java.util.Map;
 import java.util.UUID;
 
 import static com.epam.dlab.cloud.CloudProvider.*;
@@ -196,7 +197,8 @@
 
 	@SuppressWarnings("unchecked")
 	public <T extends ExploratoryCreateDTO<T>> T newExploratoryCreate(Exploratory exploratory, UserInfo userInfo,
-																	  ExploratoryGitCredsDTO exploratoryGitCredsDTO) {
+																	  ExploratoryGitCredsDTO exploratoryGitCredsDTO,
+																	  Map<String, String> tags) {
 
 		T exploratoryCreate;
 
@@ -220,7 +222,6 @@
 				exploratoryCreate = (T) newResourceSysBaseDTO(userInfo, ExploratoryCreateGcp.class)
 						.withNotebookInstanceType(exploratory.getShape());
 				break;
-
 			default:
 				throw new IllegalArgumentException(UNSUPPORTED_CLOUD_PROVIDER_MESSAGE + cloudProvider());
 		}
@@ -230,7 +231,10 @@
 				.withApplicationName(getApplicationNameFromImage(exploratory.getDockerImage()))
 				.withGitCreds(exploratoryGitCredsDTO.getGitCreds())
 				.withImageName(exploratory.getImageName())
-				.withClusterConfig(exploratory.getClusterConfig());
+				.withClusterConfig(exploratory.getClusterConfig())
+				.withProject(exploratory.getProject())
+				.withEndpoint(exploratory.getEndpoint())
+				.withTags(tags);
 	}
 
 	@SuppressWarnings("unchecked")
@@ -247,14 +251,16 @@
 						.withGitCreds(exploratoryGitCredsDTO.getGitCreds())
 						.withNotebookImage(userInstance.getImageName())
 						.withExploratoryName(userInstance.getExploratoryName())
-						.withReuploadKeyRequired(userInstance.isReuploadKeyRequired());
+						.withReuploadKeyRequired(userInstance.isReuploadKeyRequired())
+						.withProject(userInstance.getProject());
 			case AZURE:
 				T exploratoryStart = (T) newResourceSysBaseDTO(userInfo, ExploratoryActionStartAzure.class)
 						.withNotebookInstanceName(userInstance.getExploratoryId())
 						.withGitCreds(exploratoryGitCredsDTO.getGitCreds())
 						.withNotebookImage(userInstance.getImageName())
 						.withExploratoryName(userInstance.getExploratoryName())
-						.withReuploadKeyRequired(userInstance.isReuploadKeyRequired());
+						.withReuploadKeyRequired(userInstance.isReuploadKeyRequired())
+						.withProject(userInstance.getProject());
 
 				if (settingsDAO.isAzureDataLakeEnabled()) {
 					((ExploratoryActionStartAzure) exploratoryStart)
@@ -292,7 +298,8 @@
 				.withNotebookImage(userInstance.getImageName())
 				.withExploratoryName(userInstance.getExploratoryName())
 				.withNotebookImage(userInstance.getImageName())
-				.withReuploadKeyRequired(userInstance.isReuploadKeyRequired());
+				.withReuploadKeyRequired(userInstance.isReuploadKeyRequired())
+				.withProject(userInstance.getProject());
 	}
 
 	public ExploratoryGitCredsUpdateDTO newGitCredentialsUpdate(UserInfo userInfo, UserInstanceDTO instanceDTO,
@@ -301,6 +308,7 @@
 		return newResourceSysBaseDTO(userInfo, ExploratoryGitCredsUpdateDTO.class)
 				.withNotebookImage(instanceDTO.getImageName())
 				.withApplicationName(getApplicationNameFromImage(instanceDTO.getImageName()))
+				.withProject(instanceDTO.getProject())
 				.withNotebookInstanceName(instanceDTO.getExploratoryId())
 				.withExploratoryName(instanceDTO.getExploratoryName())
 				.withGitCreds(exploratoryGitCredsDTO.getGitCreds());
@@ -314,6 +322,7 @@
 				.withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
 				.withNotebookInstanceName(userInstance.getExploratoryId())
 				.withExploratoryName(userInstance.getExploratoryName())
+				.withProject(userInstance.getProject())
 				.withLibs(libs);
 	}
 
@@ -323,6 +332,7 @@
 		checkInappropriateCloudProviderOrElseThrowException();
 		return (T) newResourceSysBaseDTO(userInfo, ExploratoryActionDTO.class)
 				.withNotebookInstanceName(userInstance.getExploratoryId())
+				.withProject(userInstance.getProject())
 				.withNotebookImage(userInstance.getImageName())
 				.withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
 				.withExploratoryName(userInstance.getExploratoryName());
@@ -337,6 +347,7 @@
 				.withComputationalId(computationalResource.getComputationalId())
 				.withComputationalName(computationalResource.getComputationalName())
 				.withExploratoryName(userInstance.getExploratoryName())
+				.withProject(userInstance.getProject())
 				.withComputationalImage(computationalResource.getImageName())
 				.withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
 				.withLibs(libs);
@@ -351,6 +362,7 @@
 		checkInappropriateCloudProviderOrElseThrowException();
 		return (T) newResourceSysBaseDTO(userInfo, LibListComputationalDTO.class)
 				.withComputationalId(computationalResource.getComputationalId())
+				.withProject(userInstance.getProject())
 				.withComputationalImage(computationalResource.getImageName())
 				.withLibCacheKey(ExploratoryLibCache.libraryCacheKey(userInstance))
 				.withApplicationName(getApplicationNameFromImage(userInstance.getImageName()));
@@ -396,7 +408,8 @@
 				.withComputationalName(form.getName())
 				.withNotebookTemplateName(userInstance.getTemplateName())
 				.withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
-				.withNotebookInstanceName(userInstance.getExploratoryId());
+				.withNotebookInstanceName(userInstance.getExploratoryId())
+				.withProject(userInstance.getProject());
 	}
 
 	@SuppressWarnings("unchecked")
@@ -445,7 +458,8 @@
 				.withComputationalName(form.getName())
 				.withNotebookTemplateName(userInstance.getTemplateName())
 				.withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
-				.withNotebookInstanceName(userInstance.getExploratoryId());
+				.withNotebookInstanceName(userInstance.getExploratoryId())
+				.withProject(userInstance.getProject());
 	}
 
 	@SuppressWarnings("unchecked")
@@ -454,7 +468,8 @@
 																		String exploratoryId,
 																		String computationalName,
 																		String computationalId,
-																		DataEngineType dataEngineType) {
+																		DataEngineType dataEngineType,
+																		String project) {
 		T computationalTerminate;
 
 		switch (cloudProvider()) {
@@ -485,7 +500,8 @@
 		return computationalTerminate
 				.withExploratoryName(exploratoryName)
 				.withComputationalName(computationalName)
-				.withNotebookInstanceName(exploratoryId);
+				.withNotebookInstanceName(exploratoryId)
+				.withProject(project);
 	}
 
 	@SuppressWarnings("unchecked")
@@ -496,7 +512,8 @@
 				.withExploratoryName(exploratory.getExploratoryName())
 				.withComputationalName(computationalName)
 				.withNotebookInstanceName(exploratory.getExploratoryId())
-				.withApplicationName(getApplicationNameFromImage(exploratory.getImageName()));
+				.withApplicationName(getApplicationNameFromImage(exploratory.getImageName()))
+				.withProject(exploratory.getProject());
 	}
 
 	@SuppressWarnings("unchecked")
@@ -506,7 +523,8 @@
 				.withExploratoryName(exploratory.getExploratoryName())
 				.withComputationalName(computationalName)
 				.withNotebookInstanceName(exploratory.getExploratoryId())
-				.withApplicationName(getApplicationNameFromImage(exploratory.getImageName()));
+				.withApplicationName(getApplicationNameFromImage(exploratory.getImageName()))
+				.withProject(exploratory.getProject());
 	}
 
 	@SuppressWarnings("unchecked")
@@ -514,6 +532,7 @@
 																	   String imageName) {
 		checkInappropriateCloudProviderOrElseThrowException();
 		return (T) newResourceSysBaseDTO(userInfo, ExploratoryImageDTO.class)
+				.withProject(userInstance.getProject())
 				.withNotebookInstanceName(userInstance.getExploratoryId())
 				.withExploratoryName(userInstance.getExploratoryName())
 				.withApplicationName(getApplicationNameFromImage(userInstance.getImageName()))
@@ -586,7 +605,7 @@
 		return dto;
 
 
-    }
+	}
 
 	public ExploratoryCheckInactivityAction newExploratoryCheckInactivityAction(UserInfo userInfo,
 																				UserInstanceDTO userInstance) {
diff --git a/services/self-service/src/main/resources/webapp/angular.json b/services/self-service/src/main/resources/webapp/angular.json
index 7969eb8..1b5825f 100644
--- a/services/self-service/src/main/resources/webapp/angular.json
+++ b/services/self-service/src/main/resources/webapp/angular.json
@@ -22,11 +22,18 @@
               "src/favicon.ico"
             ],
             "styles": [
+              {
+                "input": "node_modules/@angular/material/prebuilt-themes/deeppurple-amber.css"
+              },
               "src/styles.scss",
-              "node_modules/ngx-toastr/toastr.css" 
+              "node_modules/ngx-toastr/toastr.css"
             ],
+            "stylePreprocessorOptions": {
+              "includePaths": [
+                "src/assets/styles"
+              ]
+            },
             "scripts": [
-              "node_modules/hammerjs/hammer.min.js"
             ]
           },
           "configurations": {
@@ -74,11 +81,12 @@
             "polyfills": "src/polyfills.ts",
             "tsConfig": "src/tsconfig.spec.json",
             "scripts": [
-              "node_modules/hammerjs/hammer.min.js"
             ],
             "styles": [
+              {
+                "input": "node_modules/@angular/material/prebuilt-themes/deeppurple-amber.css"
+              },
               "src/styles.scss",
-              "node_modules/ng2-toastr/bundles/ng2-toastr.min.css",
               "src/assets/fonts/iconfont/material-icons.css"
             ],
             "assets": [
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 602e119..74c3766 100644
--- a/services/self-service/src/main/resources/webapp/package-lock.json
+++ b/services/self-service/src/main/resources/webapp/package-lock.json
@@ -417,24 +417,28 @@
           "dependencies": {
             "abbrev": {
               "version": "1.1.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+              "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
               "dev": true,
               "optional": true
             },
             "ansi-regex": {
               "version": "2.1.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+              "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
               "dev": true
             },
             "aproba": {
               "version": "1.2.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+              "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
               "dev": true,
               "optional": true
             },
             "are-we-there-yet": {
               "version": "1.1.5",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+              "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -444,12 +448,14 @@
             },
             "balanced-match": {
               "version": "1.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+              "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
               "dev": true
             },
             "brace-expansion": {
               "version": "1.1.11",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+              "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
               "dev": true,
               "requires": {
                 "balanced-match": "1.0.0",
@@ -458,34 +464,40 @@
             },
             "chownr": {
               "version": "1.1.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
+              "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
               "dev": true,
               "optional": true
             },
             "code-point-at": {
               "version": "1.1.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+              "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
               "dev": true
             },
             "concat-map": {
               "version": "0.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+              "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
               "dev": true
             },
             "console-control-strings": {
               "version": "1.1.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+              "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
               "dev": true
             },
             "core-util-is": {
               "version": "1.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+              "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
               "dev": true,
               "optional": true
             },
             "debug": {
               "version": "2.6.9",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+              "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -494,25 +506,29 @@
             },
             "deep-extend": {
               "version": "0.6.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+              "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
               "dev": true,
               "optional": true
             },
             "delegates": {
               "version": "1.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+              "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
               "dev": true,
               "optional": true
             },
             "detect-libc": {
               "version": "1.0.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+              "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
               "dev": true,
               "optional": true
             },
             "fs-minipass": {
               "version": "1.2.5",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
+              "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -521,13 +537,15 @@
             },
             "fs.realpath": {
               "version": "1.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+              "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
               "dev": true,
               "optional": true
             },
             "gauge": {
               "version": "2.7.4",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+              "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
               "dev": true,
               "optional": true,
               "requires": {
@@ -543,7 +561,8 @@
             },
             "glob": {
               "version": "7.1.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+              "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -557,13 +576,15 @@
             },
             "has-unicode": {
               "version": "2.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+              "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
               "dev": true,
               "optional": true
             },
             "iconv-lite": {
               "version": "0.4.24",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+              "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -572,7 +593,8 @@
             },
             "ignore-walk": {
               "version": "3.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
+              "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -581,7 +603,8 @@
             },
             "inflight": {
               "version": "1.0.6",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+              "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
               "dev": true,
               "optional": true,
               "requires": {
@@ -591,18 +614,21 @@
             },
             "inherits": {
               "version": "2.0.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+              "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
               "dev": true
             },
             "ini": {
               "version": "1.3.5",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+              "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
               "dev": true,
               "optional": true
             },
             "is-fullwidth-code-point": {
               "version": "1.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+              "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
               "dev": true,
               "requires": {
                 "number-is-nan": "1.0.1"
@@ -610,13 +636,15 @@
             },
             "isarray": {
               "version": "1.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+              "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
               "dev": true,
               "optional": true
             },
             "minimatch": {
               "version": "3.0.4",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+              "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
               "dev": true,
               "requires": {
                 "brace-expansion": "1.1.11"
@@ -624,12 +652,14 @@
             },
             "minimist": {
               "version": "0.0.8",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+              "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
               "dev": true
             },
             "minipass": {
               "version": "2.3.5",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
+              "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
               "dev": true,
               "requires": {
                 "safe-buffer": "5.1.2",
@@ -638,7 +668,8 @@
             },
             "minizlib": {
               "version": "1.2.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
+              "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -647,7 +678,8 @@
             },
             "mkdirp": {
               "version": "0.5.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+              "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
               "dev": true,
               "requires": {
                 "minimist": "0.0.8"
@@ -655,13 +687,15 @@
             },
             "ms": {
               "version": "2.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+              "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
               "dev": true,
               "optional": true
             },
             "needle": {
               "version": "2.2.4",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz",
+              "integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -672,7 +706,8 @@
             },
             "node-pre-gyp": {
               "version": "0.10.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz",
+              "integrity": "sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -690,7 +725,8 @@
             },
             "nopt": {
               "version": "4.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
+              "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
               "dev": true,
               "optional": true,
               "requires": {
@@ -700,13 +736,15 @@
             },
             "npm-bundled": {
               "version": "1.0.5",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz",
+              "integrity": "sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g==",
               "dev": true,
               "optional": true
             },
             "npm-packlist": {
               "version": "1.2.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.2.0.tgz",
+              "integrity": "sha512-7Mni4Z8Xkx0/oegoqlcao/JpPCPEMtUvsmB0q7mgvlMinykJLSRTYuFqoQLYgGY8biuxIeiHO+QNJKbCfljewQ==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -716,7 +754,8 @@
             },
             "npmlog": {
               "version": "4.1.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+              "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -728,18 +767,21 @@
             },
             "number-is-nan": {
               "version": "1.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+              "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
               "dev": true
             },
             "object-assign": {
               "version": "4.1.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+              "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
               "dev": true,
               "optional": true
             },
             "once": {
               "version": "1.4.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+              "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
               "dev": true,
               "requires": {
                 "wrappy": "1.0.2"
@@ -747,19 +789,22 @@
             },
             "os-homedir": {
               "version": "1.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+              "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
               "dev": true,
               "optional": true
             },
             "os-tmpdir": {
               "version": "1.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+              "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
               "dev": true,
               "optional": true
             },
             "osenv": {
               "version": "0.1.5",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
+              "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -769,19 +814,22 @@
             },
             "path-is-absolute": {
               "version": "1.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+              "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
               "dev": true,
               "optional": true
             },
             "process-nextick-args": {
               "version": "2.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+              "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
               "dev": true,
               "optional": true
             },
             "rc": {
               "version": "1.2.8",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+              "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -793,7 +841,8 @@
               "dependencies": {
                 "minimist": {
                   "version": "1.2.0",
-                  "bundled": true,
+                  "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+                  "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
                   "dev": true,
                   "optional": true
                 }
@@ -801,7 +850,8 @@
             },
             "readable-stream": {
               "version": "2.3.6",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+              "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -816,7 +866,8 @@
             },
             "rimraf": {
               "version": "2.6.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+              "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -825,42 +876,49 @@
             },
             "safe-buffer": {
               "version": "5.1.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+              "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
               "dev": true
             },
             "safer-buffer": {
               "version": "2.1.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+              "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
               "dev": true,
               "optional": true
             },
             "sax": {
               "version": "1.2.4",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+              "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
               "dev": true,
               "optional": true
             },
             "semver": {
               "version": "5.6.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
+              "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
               "dev": true,
               "optional": true
             },
             "set-blocking": {
               "version": "2.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+              "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
               "dev": true,
               "optional": true
             },
             "signal-exit": {
               "version": "3.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+              "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
               "dev": true,
               "optional": true
             },
             "string-width": {
               "version": "1.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+              "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
               "dev": true,
               "requires": {
                 "code-point-at": "1.1.0",
@@ -870,7 +928,8 @@
             },
             "string_decoder": {
               "version": "1.1.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+              "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -879,7 +938,8 @@
             },
             "strip-ansi": {
               "version": "3.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+              "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
               "dev": true,
               "requires": {
                 "ansi-regex": "2.1.1"
@@ -887,13 +947,15 @@
             },
             "strip-json-comments": {
               "version": "2.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+              "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
               "dev": true,
               "optional": true
             },
             "tar": {
               "version": "4.4.8",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz",
+              "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -908,13 +970,15 @@
             },
             "util-deprecate": {
               "version": "1.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+              "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
               "dev": true,
               "optional": true
             },
             "wide-align": {
               "version": "1.1.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+              "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -923,12 +987,14 @@
             },
             "wrappy": {
               "version": "1.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+              "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
               "dev": true
             },
             "yallist": {
               "version": "3.0.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
+              "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
               "dev": true
             }
           }
@@ -1097,19 +1163,28 @@
       }
     },
     "@angular/animations": {
-      "version": "8.0.0-beta.2",
-      "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-8.0.0-beta.2.tgz",
-      "integrity": "sha512-Nc6iOJtoUvjKC+yfg+zOZKH/i1J98T+OtBxVSc1usAil21VqhhGyze0/ISsbsYrN4/QH+mH0LMb/tIvPd18hKg==",
+      "version": "7.2.15",
+      "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-7.2.15.tgz",
+      "integrity": "sha512-8oBt3HLgd2+kyJHUgsd7OzKCCss67t2sch15XNoIWlOLfxclqU+EfFE6t/vCzpT8/+lpZS6LU9ZrTnb+UBj5jg==",
       "requires": {
         "tslib": "1.9.3"
       }
     },
     "@angular/cdk": {
-      "version": "6.4.7",
-      "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-6.4.7.tgz",
-      "integrity": "sha512-18x0U66fLD5kGQWZ9n3nb75xQouXlWs7kUDaTd8HTrHpT1s2QIAqlLd1KxfrYiVhsEC2jPQaoiae7VnBlcvkBg==",
+      "version": "7.3.7",
+      "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-7.3.7.tgz",
+      "integrity": "sha512-xbXxhHHKGkVuW6K7pzPmvpJXIwpl0ykBnvA2g+/7Sgy5Pd35wCC+UtHD9RYczDM/mkygNxMQtagyCErwFnDtQA==",
       "requires": {
+        "parse5": "5.1.0",
         "tslib": "1.9.3"
+      },
+      "dependencies": {
+        "parse5": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz",
+          "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==",
+          "optional": true
+        }
       }
     },
     "@angular/cli": {
@@ -1366,20 +1441,11 @@
       }
     },
     "@angular/material": {
-      "version": "6.4.7",
-      "resolved": "https://registry.npmjs.org/@angular/material/-/material-6.4.7.tgz",
-      "integrity": "sha512-SdNx7Xovi24Kw9eU6lkLhY/7f2M7L9F+/uh6XuPr4jbGgCUVVpeeVI5ztZhsZRbj1sN+/r1p5w8u62apWWl5Ww==",
+      "version": "7.3.7",
+      "resolved": "https://registry.npmjs.org/@angular/material/-/material-7.3.7.tgz",
+      "integrity": "sha512-Eq+7frkeNGkLOfEtmkmJgR+AgoWajOipXZWWfCSamNfpCcPof82DwvGOpAmgGni9FuN2XFQdqP5MoaffQzIvUA==",
       "requires": {
-        "parse5": "5.1.0",
         "tslib": "1.9.3"
-      },
-      "dependencies": {
-        "parse5": {
-          "version": "5.1.0",
-          "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz",
-          "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ==",
-          "optional": true
-        }
       }
     },
     "@angular/material-moment-adapter": {
@@ -1506,12 +1572,6 @@
         }
       }
     },
-    "@types/jasmine": {
-      "version": "2.5.38",
-      "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.5.38.tgz",
-      "integrity": "sha1-pDeRJMSSHU4h3lTsdGacnps1Zxc=",
-      "dev": true
-    },
     "@types/moment-timezone": {
       "version": "0.5.10",
       "resolved": "https://registry.npmjs.org/@types/moment-timezone/-/moment-timezone-0.5.10.tgz",
@@ -1527,18 +1587,6 @@
       "integrity": "sha512-Z/67L97+6H1qJiEEHSN1SQapkWjDss1D90rAnFcQ6UxKkah9juzotK5UNEP1bDv/0lJ3NAQTnVfc/JWdgCGruA==",
       "dev": true
     },
-    "@types/q": {
-      "version": "0.0.32",
-      "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz",
-      "integrity": "sha1-vShOV8hPEyXacCur/IKlMoGQwMU=",
-      "dev": true
-    },
-    "@types/selenium-webdriver": {
-      "version": "2.53.42",
-      "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-2.53.42.tgz",
-      "integrity": "sha1-dMt3+2BS7a/yqJhN2v2I1BnyXKw=",
-      "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",
@@ -1809,36 +1857,12 @@
       "integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw==",
       "dev": true
     },
-    "adm-zip": {
-      "version": "0.4.7",
-      "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz",
-      "integrity": "sha1-hgbCy/HEJs6MjsABdER/1Jtur8E=",
+    "acorn-walk": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz",
+      "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==",
       "dev": true
     },
-    "after": {
-      "version": "0.8.2",
-      "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz",
-      "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=",
-      "dev": true
-    },
-    "agent-base": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.1.1.tgz",
-      "integrity": "sha1-1t4Q1a9hMtW9aSQn1G/FOFOQlMc=",
-      "dev": true,
-      "requires": {
-        "extend": "3.0.1",
-        "semver": "5.0.3"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "5.0.3",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz",
-          "integrity": "sha1-d0Zt5YnNXTyV8TiqeLxWmjy10no=",
-          "dev": true
-        }
-      }
-    },
     "agentkeepalive": {
       "version": "3.5.2",
       "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-3.5.2.tgz",
@@ -1886,17 +1910,6 @@
       "integrity": "sha512-CMzN9S62ZOO4sA/mJZIO4S++ZM7KFWzH3PPWkveLhy4OZ9i1/VatgwWMD46w/XbGCBy7Ye0gCk+Za6mmyfKK7g==",
       "dev": true
     },
-    "align-text": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
-      "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
-      "dev": true,
-      "requires": {
-        "kind-of": "3.2.2",
-        "longest": "1.0.1",
-        "repeat-string": "1.6.1"
-      }
-    },
     "amdefine": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
@@ -1949,21 +1962,6 @@
         "normalize-path": "2.1.1"
       }
     },
-    "app-root-path": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-2.2.1.tgz",
-      "integrity": "sha512-91IFKeKk7FjfmezPKkwtaRvSpnUc4gDwPAjA1YZ9Gn0q0PPeW+vbeUsZuyDwjI7+QTHhcLen2v25fi/AmhvbJA==",
-      "dev": true
-    },
-    "append-transform": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-0.4.0.tgz",
-      "integrity": "sha1-126/jKlNJ24keja61EpLdKthGZE=",
-      "dev": true,
-      "requires": {
-        "default-require-extensions": "1.0.0"
-      }
-    },
     "aproba": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
@@ -2022,12 +2020,6 @@
       "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==",
       "dev": true
     },
-    "array-slice": {
-      "version": "0.2.3",
-      "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz",
-      "integrity": "sha1-3Tz7gO15c6dRF82sabC5nshhhvU=",
-      "dev": true
-    },
     "array-union": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
@@ -2049,12 +2041,6 @@
       "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
       "dev": true
     },
-    "arraybuffer.slice": {
-      "version": "0.0.6",
-      "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz",
-      "integrity": "sha1-8zshWfBTKj8xB6JywMz70a0peco=",
-      "dev": true
-    },
     "arrify": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
@@ -2144,6 +2130,12 @@
       "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=",
       "dev": true
     },
+    "async-limiter": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
+      "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==",
+      "dev": true
+    },
     "asynckit": {
       "version": "0.4.0",
       "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@@ -2180,7 +2172,8 @@
       "version": "1.6.0",
       "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
       "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=",
-      "dev": true
+      "dev": true,
+      "optional": true
     },
     "babel-code-frame": {
       "version": "6.26.0",
@@ -2284,12 +2277,6 @@
       "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
       "dev": true
     },
-    "backo2": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
-      "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=",
-      "dev": true
-    },
     "base": {
       "version": "0.11.2",
       "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
@@ -2363,24 +2350,12 @@
         }
       }
     },
-    "base64-arraybuffer": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz",
-      "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=",
-      "dev": true
-    },
     "base64-js": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
       "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==",
       "dev": true
     },
-    "base64id": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz",
-      "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=",
-      "dev": true
-    },
     "batch": {
       "version": "0.6.1",
       "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
@@ -2397,13 +2372,16 @@
         "tweetnacl": "0.14.5"
       }
     },
-    "better-assert": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz",
-      "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=",
+    "bfj": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.1.tgz",
+      "integrity": "sha512-+GUNvzHR4nRyGybQc2WpNJL4MJazMuvf92ueIyA0bIkPRwhhQu3IfZQ2PSoVPpCBJfmoSdOxu5rnotfFLlvYRQ==",
       "dev": true,
       "requires": {
-        "callsite": "1.0.0"
+        "bluebird": "3.5.1",
+        "check-types": "7.4.0",
+        "hoopy": "0.1.4",
+        "tryer": "1.0.1"
       }
     },
     "big.js": {
@@ -2418,12 +2396,6 @@
       "integrity": "sha1-muuabF6IY4qtFx4Wf1kAq+JINdA=",
       "dev": true
     },
-    "blob": {
-      "version": "0.0.4",
-      "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz",
-      "integrity": "sha1-vPEwUspURj8w+fx+lbmkdjCpSSE=",
-      "dev": true
-    },
     "block-stream": {
       "version": "0.0.9",
       "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
@@ -2433,15 +2405,6 @@
         "inherits": "2.0.3"
       }
     },
-    "blocking-proxy": {
-      "version": "0.0.5",
-      "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-0.0.5.tgz",
-      "integrity": "sha1-RikF4Nz76pcPQao3Ij3anAexkSs=",
-      "dev": true,
-      "requires": {
-        "minimist": "1.2.0"
-      }
-    },
     "bluebird": {
       "version": "3.5.1",
       "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
@@ -2454,24 +2417,6 @@
       "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==",
       "dev": true
     },
-    "body-parser": {
-      "version": "1.18.2",
-      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz",
-      "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=",
-      "dev": true,
-      "requires": {
-        "bytes": "3.0.0",
-        "content-type": "1.0.4",
-        "debug": "2.6.9",
-        "depd": "1.1.1",
-        "http-errors": "1.6.2",
-        "iconv-lite": "0.4.19",
-        "on-finished": "2.3.0",
-        "qs": "6.5.1",
-        "raw-body": "2.3.2",
-        "type-is": "1.6.15"
-      }
-    },
     "bonjour": {
       "version": "3.5.0",
       "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz",
@@ -2491,6 +2436,7 @@
       "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz",
       "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=",
       "dev": true,
+      "optional": true,
       "requires": {
         "hoek": "4.2.0"
       }
@@ -2775,12 +2721,6 @@
         }
       }
     },
-    "callsite": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz",
-      "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=",
-      "dev": true
-    },
     "camelcase": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
@@ -2815,17 +2755,6 @@
       "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
       "dev": true
     },
-    "center-align": {
-      "version": "0.1.3",
-      "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
-      "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "align-text": "0.1.4",
-        "lazy-cache": "1.0.4"
-      }
-    },
     "chalk": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
@@ -2853,6 +2782,12 @@
       "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==",
       "dev": true
     },
+    "check-types": {
+      "version": "7.4.0",
+      "resolved": "https://registry.npmjs.org/check-types/-/check-types-7.4.0.tgz",
+      "integrity": "sha512-YbulWHdfP99UfZ73NcUDlNJhEIDgm9Doq9GhpyXbF+7Aegi3CVV7qqMCKTTqJxlvEvnQBp9IA+dxsGN6xK/nSg==",
+      "dev": true
+    },
     "chokidar": {
       "version": "1.7.0",
       "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
@@ -2861,7 +2796,7 @@
       "requires": {
         "anymatch": "1.3.2",
         "async-each": "1.0.1",
-        "fsevents": "1.1.2",
+        "fsevents": "1.2.9",
         "glob-parent": "2.0.0",
         "inherits": "2.0.3",
         "is-binary-path": "1.0.1",
@@ -3042,20 +2977,6 @@
       "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
       "dev": true
     },
-    "codelyzer": {
-      "version": "3.2.2",
-      "resolved": "https://registry.npmjs.org/codelyzer/-/codelyzer-3.2.2.tgz",
-      "integrity": "sha512-VNvW9gRThsqRarEnLioiILd0Pdk0yCq/7cVgYvqHpC+3CHqfnrJfmXjoana7vzWfSis+9pODXofjCWX+nlU9Gw==",
-      "dev": true,
-      "requires": {
-        "app-root-path": "2.2.1",
-        "css-selector-tokenizer": "0.7.1",
-        "cssauron": "1.4.0",
-        "semver-dsl": "1.0.1",
-        "source-map": "0.5.7",
-        "sprintf-js": "1.0.3"
-      }
-    },
     "collection-visit": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
@@ -3081,21 +3002,6 @@
       "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
       "dev": true
     },
-    "colors": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
-      "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
-      "dev": true
-    },
-    "combine-lists": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz",
-      "integrity": "sha1-RYwH4J4NkA/Ci3Cj/sLazR0st/Y=",
-      "dev": true,
-      "requires": {
-        "lodash": "4.17.4"
-      }
-    },
     "combined-stream": {
       "version": "1.0.5",
       "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
@@ -3117,24 +3023,6 @@
       "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
       "dev": true
     },
-    "component-bind": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz",
-      "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=",
-      "dev": true
-    },
-    "component-emitter": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz",
-      "integrity": "sha1-KWWU8nU9qmOZbSrwjRWpURbJrsM=",
-      "dev": true
-    },
-    "component-inherit": {
-      "version": "0.0.3",
-      "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz",
-      "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=",
-      "dev": true
-    },
     "compressible": {
       "version": "2.0.15",
       "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.15.tgz",
@@ -3193,35 +3081,6 @@
         "typedarray": "0.0.6"
       }
     },
-    "connect": {
-      "version": "3.6.5",
-      "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.5.tgz",
-      "integrity": "sha1-+43ee6B2OHfQ7J352sC0tA5yx9o=",
-      "dev": true,
-      "requires": {
-        "debug": "2.6.9",
-        "finalhandler": "1.0.6",
-        "parseurl": "1.3.2",
-        "utils-merge": "1.0.1"
-      },
-      "dependencies": {
-        "finalhandler": {
-          "version": "1.0.6",
-          "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.6.tgz",
-          "integrity": "sha1-AHrqM9Gk0+QgF/YkhIrVjSEvgU8=",
-          "dev": true,
-          "requires": {
-            "debug": "2.6.9",
-            "encodeurl": "1.0.1",
-            "escape-html": "1.0.3",
-            "on-finished": "2.3.0",
-            "parseurl": "1.3.2",
-            "statuses": "1.3.1",
-            "unpipe": "1.0.0"
-          }
-        }
-      }
-    },
     "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",
@@ -3522,6 +3381,7 @@
       "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz",
       "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=",
       "dev": true,
+      "optional": true,
       "requires": {
         "boom": "5.2.0"
       },
@@ -3531,6 +3391,7 @@
           "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz",
           "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==",
           "dev": true,
+          "optional": true,
           "requires": {
             "hoek": "4.2.0"
           }
@@ -3562,32 +3423,6 @@
       "integrity": "sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs=",
       "dev": true
     },
-    "css-selector-tokenizer": {
-      "version": "0.7.1",
-      "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz",
-      "integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==",
-      "dev": true,
-      "requires": {
-        "cssesc": "0.1.0",
-        "fastparse": "1.1.2",
-        "regexpu-core": "1.0.0"
-      }
-    },
-    "cssauron": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/cssauron/-/cssauron-1.4.0.tgz",
-      "integrity": "sha1-pmAt/34EqDBtwNuaVR6S6LVmKtg=",
-      "dev": true,
-      "requires": {
-        "through": "2.3.8"
-      }
-    },
-    "cssesc": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz",
-      "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=",
-      "dev": true
-    },
     "currently-unhandled": {
       "version": "0.4.1",
       "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
@@ -3597,12 +3432,6 @@
         "array-find-index": "1.0.2"
       }
     },
-    "custom-event": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz",
-      "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=",
-      "dev": true
-    },
     "cyclist": {
       "version": "0.2.2",
       "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz",
@@ -3672,15 +3501,6 @@
         "ip-regex": "2.1.0"
       }
     },
-    "default-require-extensions": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-1.0.0.tgz",
-      "integrity": "sha1-836hXT4T/9m0N9M+GnW1+5eHTLg=",
-      "dev": true,
-      "requires": {
-        "strip-bom": "2.0.0"
-      }
-    },
     "define-property": {
       "version": "2.0.2",
       "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
@@ -3734,21 +3554,6 @@
         }
       }
     },
-    "del": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
-      "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
-      "dev": true,
-      "requires": {
-        "globby": "5.0.0",
-        "is-path-cwd": "1.0.0",
-        "is-path-in-cwd": "1.0.0",
-        "object-assign": "4.1.1",
-        "pify": "2.3.0",
-        "pinkie-promise": "2.0.1",
-        "rimraf": "2.6.2"
-      }
-    },
     "delayed-stream": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
@@ -3804,12 +3609,6 @@
       "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==",
       "dev": true
     },
-    "di": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz",
-      "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=",
-      "dev": true
-    },
     "diff": {
       "version": "3.4.0",
       "resolved": "https://registry.npmjs.org/diff/-/diff-3.4.0.tgz",
@@ -3878,18 +3677,6 @@
         "buffer-indexof": "1.1.1"
       }
     },
-    "dom-serialize": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz",
-      "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=",
-      "dev": true,
-      "requires": {
-        "custom-event": "1.0.1",
-        "ent": "2.2.0",
-        "extend": "3.0.1",
-        "void-elements": "2.0.1"
-      }
-    },
     "domain-browser": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
@@ -3901,6 +3688,12 @@
       "resolved": "https://registry.npmjs.org/domino/-/domino-2.1.1.tgz",
       "integrity": "sha512-fqoTi6oQ881wYRENIEmz78hKVoc3X9HqVpklo419yxzebys6dtU5c83iVh3UYvvexPFdAuwlDYCsUM9//CrMMg=="
     },
+    "duplexer": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
+      "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
+      "dev": true
+    },
     "duplexify": {
       "version": "3.7.1",
       "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
@@ -3929,6 +3722,12 @@
       "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
       "dev": true
     },
+    "ejs": {
+      "version": "2.6.1",
+      "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.1.tgz",
+      "integrity": "sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ==",
+      "dev": true
+    },
     "electron-to-chromium": {
       "version": "1.3.113",
       "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.113.tgz",
@@ -3956,12 +3755,6 @@
       "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
       "dev": true
     },
-    "encodeurl": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz",
-      "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=",
-      "dev": true
-    },
     "encoding": {
       "version": "0.1.12",
       "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz",
@@ -3980,104 +3773,6 @@
         "once": "1.4.0"
       }
     },
-    "engine.io": {
-      "version": "1.8.2",
-      "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.8.2.tgz",
-      "integrity": "sha1-a1m+cws0jAElsKRYneHDVavPen4=",
-      "dev": true,
-      "requires": {
-        "accepts": "1.3.3",
-        "base64id": "1.0.0",
-        "cookie": "0.3.1",
-        "debug": "2.3.3",
-        "engine.io-parser": "1.3.2",
-        "ws": "1.1.1"
-      },
-      "dependencies": {
-        "accepts": {
-          "version": "1.3.3",
-          "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz",
-          "integrity": "sha1-w8p0NJOGSMPg2cHjKN1otiLChMo=",
-          "dev": true,
-          "requires": {
-            "mime-types": "2.1.17",
-            "negotiator": "0.6.1"
-          }
-        },
-        "debug": {
-          "version": "2.3.3",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
-          "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
-          "dev": true,
-          "requires": {
-            "ms": "0.7.2"
-          }
-        },
-        "ms": {
-          "version": "0.7.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
-          "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
-          "dev": true
-        }
-      }
-    },
-    "engine.io-client": {
-      "version": "1.8.2",
-      "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.8.2.tgz",
-      "integrity": "sha1-w4dnVH8qfRhPV1L28K1QEAZwN2Y=",
-      "dev": true,
-      "requires": {
-        "component-emitter": "1.2.1",
-        "component-inherit": "0.0.3",
-        "debug": "2.3.3",
-        "engine.io-parser": "1.3.2",
-        "has-cors": "1.1.0",
-        "indexof": "0.0.1",
-        "parsejson": "0.0.3",
-        "parseqs": "0.0.5",
-        "parseuri": "0.0.5",
-        "ws": "1.1.1",
-        "xmlhttprequest-ssl": "1.5.3",
-        "yeast": "0.1.2"
-      },
-      "dependencies": {
-        "component-emitter": {
-          "version": "1.2.1",
-          "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
-          "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
-          "dev": true
-        },
-        "debug": {
-          "version": "2.3.3",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
-          "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
-          "dev": true,
-          "requires": {
-            "ms": "0.7.2"
-          }
-        },
-        "ms": {
-          "version": "0.7.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
-          "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
-          "dev": true
-        }
-      }
-    },
-    "engine.io-parser": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.3.2.tgz",
-      "integrity": "sha1-k3sHnwAH0Ik+xW1GyyILjLQ1Igo=",
-      "dev": true,
-      "requires": {
-        "after": "0.8.2",
-        "arraybuffer.slice": "0.0.6",
-        "base64-arraybuffer": "0.1.5",
-        "blob": "0.0.4",
-        "has-binary": "0.1.7",
-        "wtf-8": "1.0.0"
-      }
-    },
     "enhanced-resolve": {
       "version": "4.1.0",
       "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz",
@@ -4089,12 +3784,6 @@
         "tapable": "1.1.1"
       }
     },
-    "ent": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz",
-      "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=",
-      "dev": true
-    },
     "err-code": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/err-code/-/err-code-1.1.2.tgz",
@@ -4303,56 +3992,6 @@
         }
       }
     },
-    "exit": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
-      "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=",
-      "dev": true
-    },
-    "expand-braces": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/expand-braces/-/expand-braces-0.1.2.tgz",
-      "integrity": "sha1-SIsdHSRRyz06axks/AMPRMWFX+o=",
-      "dev": true,
-      "requires": {
-        "array-slice": "0.2.3",
-        "array-unique": "0.2.1",
-        "braces": "0.1.5"
-      },
-      "dependencies": {
-        "braces": {
-          "version": "0.1.5",
-          "resolved": "https://registry.npmjs.org/braces/-/braces-0.1.5.tgz",
-          "integrity": "sha1-wIVxEIUpHYt1/ddOqw+FlygHEeY=",
-          "dev": true,
-          "requires": {
-            "expand-range": "0.1.1"
-          }
-        },
-        "expand-range": {
-          "version": "0.1.1",
-          "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-0.1.1.tgz",
-          "integrity": "sha1-TLjtoJk8pW+k9B/ELzy7TMrf8EQ=",
-          "dev": true,
-          "requires": {
-            "is-number": "0.1.1",
-            "repeat-string": "0.2.2"
-          }
-        },
-        "is-number": {
-          "version": "0.1.1",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-0.1.1.tgz",
-          "integrity": "sha1-aaevEWlj1HIG7JvZtIoUIW8eOAY=",
-          "dev": true
-        },
-        "repeat-string": {
-          "version": "0.2.2",
-          "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-0.2.2.tgz",
-          "integrity": "sha1-x6jTI2BoNiBZp+RlH8aITosftK4=",
-          "dev": true
-        }
-      }
-    },
     "expand-brackets": {
       "version": "0.1.5",
       "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
@@ -4527,7 +4166,8 @@
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
       "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=",
-      "dev": true
+      "dev": true,
+      "optional": true
     },
     "extend-shallow": {
       "version": "3.0.2",
@@ -4605,12 +4245,6 @@
       "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
       "dev": true
     },
-    "fastparse": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
-      "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
-      "dev": true
-    },
     "faye-websocket": {
       "version": "0.10.0",
       "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",
@@ -4651,15 +4285,11 @@
       "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
       "dev": true
     },
-    "fileset": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/fileset/-/fileset-2.0.3.tgz",
-      "integrity": "sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA=",
-      "dev": true,
-      "requires": {
-        "glob": "7.1.2",
-        "minimatch": "3.0.4"
-      }
+    "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": "2.2.3",
@@ -4782,6 +4412,7 @@
       "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz",
       "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=",
       "dev": true,
+      "optional": true,
       "requires": {
         "asynckit": "0.4.0",
         "combined-stream": "1.0.5",
@@ -4819,15 +4450,6 @@
         "readable-stream": "2.3.3"
       }
     },
-    "fs-access": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/fs-access/-/fs-access-1.0.1.tgz",
-      "integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=",
-      "dev": true,
-      "requires": {
-        "null-check": "1.0.0"
-      }
-    },
     "fs-minipass": {
       "version": "1.2.5",
       "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
@@ -4856,362 +4478,147 @@
       "dev": true
     },
     "fsevents": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz",
-      "integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==",
+      "version": "1.2.9",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz",
+      "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==",
       "dev": true,
       "optional": true,
       "requires": {
-        "nan": "2.7.0",
-        "node-pre-gyp": "0.6.36"
+        "nan": "2.14.0",
+        "node-pre-gyp": "0.12.0"
       },
       "dependencies": {
         "abbrev": {
-          "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz",
-          "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=",
+          "version": "1.1.1",
+          "bundled": true,
           "dev": true,
           "optional": true
         },
-        "ajv": {
-          "version": "4.11.8",
-          "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
-          "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "co": "4.6.0",
-            "json-stable-stringify": "1.0.1"
-          }
-        },
         "ansi-regex": {
           "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
-          "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
+          "bundled": true,
           "dev": true
         },
         "aproba": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.1.1.tgz",
-          "integrity": "sha1-ldNgDwdxCqDpKYxyatXs8urLq6s=",
+          "version": "1.2.0",
+          "bundled": true,
           "dev": true,
           "optional": true
         },
         "are-we-there-yet": {
-          "version": "1.1.4",
-          "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz",
-          "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=",
+          "version": "1.1.5",
+          "bundled": true,
           "dev": true,
           "optional": true,
           "requires": {
             "delegates": "1.0.0",
-            "readable-stream": "2.2.9"
+            "readable-stream": "2.3.6"
           }
         },
-        "asn1": {
-          "version": "0.2.3",
-          "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
-          "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=",
-          "dev": true,
-          "optional": true
-        },
-        "assert-plus": {
-          "version": "0.2.0",
-          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz",
-          "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=",
-          "dev": true,
-          "optional": true
-        },
-        "asynckit": {
-          "version": "0.4.0",
-          "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
-          "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
-          "dev": true,
-          "optional": true
-        },
-        "aws-sign2": {
-          "version": "0.6.0",
-          "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
-          "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=",
-          "dev": true,
-          "optional": true
-        },
-        "aws4": {
-          "version": "1.6.0",
-          "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
-          "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=",
-          "dev": true,
-          "optional": true
-        },
         "balanced-match": {
-          "version": "0.4.2",
-          "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
-          "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=",
+          "version": "1.0.0",
+          "bundled": true,
           "dev": true
         },
-        "bcrypt-pbkdf": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
-          "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "tweetnacl": "0.14.5"
-          }
-        },
-        "block-stream": {
-          "version": "0.0.9",
-          "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
-          "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
-          "dev": true,
-          "requires": {
-            "inherits": "2.0.3"
-          }
-        },
-        "boom": {
-          "version": "2.10.1",
-          "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz",
-          "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=",
-          "dev": true,
-          "requires": {
-            "hoek": "2.16.3"
-          }
-        },
         "brace-expansion": {
-          "version": "1.1.7",
-          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz",
-          "integrity": "sha1-Pv/DxQ4ABTH7cg6v+A8K6O8jz1k=",
+          "version": "1.1.11",
+          "bundled": true,
           "dev": true,
           "requires": {
-            "balanced-match": "0.4.2",
+            "balanced-match": "1.0.0",
             "concat-map": "0.0.1"
           }
         },
-        "buffer-shims": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz",
-          "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=",
-          "dev": true
-        },
-        "caseless": {
-          "version": "0.12.0",
-          "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
-          "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=",
-          "dev": true,
-          "optional": true
-        },
-        "co": {
-          "version": "4.6.0",
-          "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
-          "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
+        "chownr": {
+          "version": "1.1.1",
+          "bundled": true,
           "dev": true,
           "optional": true
         },
         "code-point-at": {
           "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
-          "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
+          "bundled": true,
           "dev": true
         },
-        "combined-stream": {
-          "version": "1.0.5",
-          "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
-          "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
-          "dev": true,
-          "requires": {
-            "delayed-stream": "1.0.0"
-          }
-        },
         "concat-map": {
           "version": "0.0.1",
-          "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-          "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+          "bundled": true,
           "dev": true
         },
         "console-control-strings": {
           "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
-          "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
+          "bundled": true,
           "dev": true
         },
         "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
-        },
-        "cryptiles": {
-          "version": "2.0.5",
-          "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
-          "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
+          "bundled": true,
           "dev": true,
-          "optional": true,
-          "requires": {
-            "boom": "2.10.1"
-          }
-        },
-        "dashdash": {
-          "version": "1.14.1",
-          "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
-          "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "assert-plus": "1.0.0"
-          },
-          "dependencies": {
-            "assert-plus": {
-              "version": "1.0.0",
-              "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
-              "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
-              "dev": true,
-              "optional": true
-            }
-          }
+          "optional": true
         },
         "debug": {
-          "version": "2.6.8",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
-          "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
+          "version": "4.1.1",
+          "bundled": true,
           "dev": true,
           "optional": true,
           "requires": {
-            "ms": "2.0.0"
+            "ms": "2.1.1"
           }
         },
         "deep-extend": {
-          "version": "0.4.2",
-          "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz",
-          "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8=",
+          "version": "0.6.0",
+          "bundled": true,
           "dev": true,
           "optional": true
         },
-        "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
-        },
         "delegates": {
           "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
-          "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
+          "bundled": true,
           "dev": true,
           "optional": true
         },
-        "ecc-jsbn": {
-          "version": "0.1.1",
-          "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
-          "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
+        "detect-libc": {
+          "version": "1.0.3",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "fs-minipass": {
+          "version": "1.2.5",
+          "bundled": true,
           "dev": true,
           "optional": true,
           "requires": {
-            "jsbn": "0.1.1"
-          }
-        },
-        "extend": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
-          "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=",
-          "dev": true,
-          "optional": true
-        },
-        "extsprintf": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz",
-          "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=",
-          "dev": true
-        },
-        "forever-agent": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
-          "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=",
-          "dev": true,
-          "optional": true
-        },
-        "form-data": {
-          "version": "2.1.4",
-          "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz",
-          "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "asynckit": "0.4.0",
-            "combined-stream": "1.0.5",
-            "mime-types": "2.1.15"
+            "minipass": "2.3.5"
           }
         },
         "fs.realpath": {
           "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-          "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
-          "dev": true
-        },
-        "fstream": {
-          "version": "1.0.11",
-          "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz",
-          "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=",
+          "bundled": true,
           "dev": true,
-          "requires": {
-            "graceful-fs": "4.1.11",
-            "inherits": "2.0.3",
-            "mkdirp": "0.5.1",
-            "rimraf": "2.6.1"
-          }
-        },
-        "fstream-ignore": {
-          "version": "1.0.5",
-          "resolved": "https://registry.npmjs.org/fstream-ignore/-/fstream-ignore-1.0.5.tgz",
-          "integrity": "sha1-nDHa40dnAY/h0kmyTa2mfQktoQU=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "fstream": "1.0.11",
-            "inherits": "2.0.3",
-            "minimatch": "3.0.4"
-          }
+          "optional": true
         },
         "gauge": {
           "version": "2.7.4",
-          "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
-          "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
+          "bundled": true,
           "dev": true,
           "optional": true,
           "requires": {
-            "aproba": "1.1.1",
+            "aproba": "1.2.0",
             "console-control-strings": "1.1.0",
             "has-unicode": "2.0.1",
             "object-assign": "4.1.1",
             "signal-exit": "3.0.2",
             "string-width": "1.0.2",
             "strip-ansi": "3.0.1",
-            "wide-align": "1.1.2"
-          }
-        },
-        "getpass": {
-          "version": "0.1.7",
-          "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
-          "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "assert-plus": "1.0.0"
-          },
-          "dependencies": {
-            "assert-plus": {
-              "version": "1.0.0",
-              "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
-              "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
-              "dev": true,
-              "optional": true
-            }
+            "wide-align": "1.1.3"
           }
         },
         "glob": {
-          "version": "7.1.2",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
-          "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+          "version": "7.1.3",
+          "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "fs.realpath": "1.0.0",
             "inflight": "1.0.6",
@@ -5221,73 +4628,35 @@
             "path-is-absolute": "1.0.1"
           }
         },
-        "graceful-fs": {
-          "version": "4.1.11",
-          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
-          "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
-          "dev": true
-        },
-        "har-schema": {
-          "version": "1.0.5",
-          "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz",
-          "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=",
-          "dev": true,
-          "optional": true
-        },
-        "har-validator": {
-          "version": "4.2.1",
-          "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz",
-          "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "ajv": "4.11.8",
-            "har-schema": "1.0.5"
-          }
-        },
         "has-unicode": {
           "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
-          "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
+          "bundled": true,
           "dev": true,
           "optional": true
         },
-        "hawk": {
-          "version": "3.1.3",
-          "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
-          "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
+        "iconv-lite": {
+          "version": "0.4.24",
+          "bundled": true,
           "dev": true,
           "optional": true,
           "requires": {
-            "boom": "2.10.1",
-            "cryptiles": "2.0.5",
-            "hoek": "2.16.3",
-            "sntp": "1.0.9"
+            "safer-buffer": "2.1.2"
           }
         },
-        "hoek": {
-          "version": "2.16.3",
-          "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
-          "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=",
-          "dev": true
-        },
-        "http-signature": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
-          "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=",
+        "ignore-walk": {
+          "version": "3.0.1",
+          "bundled": true,
           "dev": true,
           "optional": true,
           "requires": {
-            "assert-plus": "0.2.0",
-            "jsprim": "1.4.0",
-            "sshpk": "1.13.0"
+            "minimatch": "3.0.4"
           }
         },
         "inflight": {
           "version": "1.0.6",
-          "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
-          "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+          "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
             "once": "1.4.0",
             "wrappy": "1.0.2"
@@ -5295,199 +4664,136 @@
         },
         "inherits": {
           "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
+          "bundled": true,
           "dev": true
         },
         "ini": {
-          "version": "1.3.4",
-          "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz",
-          "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=",
+          "version": "1.3.5",
+          "bundled": true,
           "dev": true,
           "optional": 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": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
+          "bundled": true,
           "dev": true,
           "requires": {
             "number-is-nan": "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,
-          "optional": true
-        },
         "isarray": {
           "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
-          "dev": true
-        },
-        "isstream": {
-          "version": "0.1.2",
-          "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
-          "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
+          "bundled": true,
           "dev": true,
           "optional": true
         },
-        "jodid25519": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz",
-          "integrity": "sha1-BtSRIlUJNBlHfUJWM2BuDpB4KWc=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "jsbn": "0.1.1"
-          }
-        },
-        "jsbn": {
-          "version": "0.1.1",
-          "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
-          "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
-          "dev": true,
-          "optional": true
-        },
-        "json-schema": {
-          "version": "0.2.3",
-          "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
-          "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
-          "dev": true,
-          "optional": true
-        },
-        "json-stable-stringify": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
-          "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "jsonify": "0.0.0"
-          }
-        },
-        "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,
-          "optional": true
-        },
-        "jsonify": {
-          "version": "0.0.0",
-          "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
-          "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
-          "dev": true,
-          "optional": true
-        },
-        "jsprim": {
-          "version": "1.4.0",
-          "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.0.tgz",
-          "integrity": "sha1-o7h+QCmNjDgFUtjMdiigu5WiKRg=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "assert-plus": "1.0.0",
-            "extsprintf": "1.0.2",
-            "json-schema": "0.2.3",
-            "verror": "1.3.6"
-          },
-          "dependencies": {
-            "assert-plus": {
-              "version": "1.0.0",
-              "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
-              "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
-              "dev": true,
-              "optional": true
-            }
-          }
-        },
-        "mime-db": {
-          "version": "1.27.0",
-          "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.27.0.tgz",
-          "integrity": "sha1-gg9XIpa70g7CXtVeW13oaeVDbrE=",
-          "dev": true
-        },
-        "mime-types": {
-          "version": "2.1.15",
-          "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.15.tgz",
-          "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=",
-          "dev": true,
-          "requires": {
-            "mime-db": "1.27.0"
-          }
-        },
         "minimatch": {
           "version": "3.0.4",
-          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
-          "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+          "bundled": true,
           "dev": true,
           "requires": {
-            "brace-expansion": "1.1.7"
+            "brace-expansion": "1.1.11"
           }
         },
         "minimist": {
           "version": "0.0.8",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
-          "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
+          "bundled": true,
           "dev": true
         },
+        "minipass": {
+          "version": "2.3.5",
+          "bundled": true,
+          "dev": true,
+          "requires": {
+            "safe-buffer": "5.1.2",
+            "yallist": "3.0.3"
+          }
+        },
+        "minizlib": {
+          "version": "1.2.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "minipass": "2.3.5"
+          }
+        },
         "mkdirp": {
           "version": "0.5.1",
-          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
-          "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+          "bundled": true,
           "dev": true,
           "requires": {
             "minimist": "0.0.8"
           }
         },
         "ms": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
+          "version": "2.1.1",
+          "bundled": true,
           "dev": true,
           "optional": true
         },
-        "node-pre-gyp": {
-          "version": "0.6.36",
-          "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz",
-          "integrity": "sha1-22BBEst04NR3VU6bUFsXq936t4Y=",
+        "needle": {
+          "version": "2.3.0",
+          "bundled": true,
           "dev": true,
           "optional": true,
           "requires": {
+            "debug": "4.1.1",
+            "iconv-lite": "0.4.24",
+            "sax": "1.2.4"
+          }
+        },
+        "node-pre-gyp": {
+          "version": "0.12.0",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "detect-libc": "1.0.3",
             "mkdirp": "0.5.1",
+            "needle": "2.3.0",
             "nopt": "4.0.1",
-            "npmlog": "4.1.0",
-            "rc": "1.2.1",
-            "request": "2.81.0",
-            "rimraf": "2.6.1",
-            "semver": "5.3.0",
-            "tar": "2.2.1",
-            "tar-pack": "3.4.0"
+            "npm-packlist": "1.4.1",
+            "npmlog": "4.1.2",
+            "rc": "1.2.8",
+            "rimraf": "2.6.3",
+            "semver": "5.7.0",
+            "tar": "4.4.8"
           }
         },
         "nopt": {
           "version": "4.0.1",
-          "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
-          "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
+          "bundled": true,
           "dev": true,
           "optional": true,
           "requires": {
-            "abbrev": "1.1.0",
-            "osenv": "0.1.4"
+            "abbrev": "1.1.1",
+            "osenv": "0.1.5"
+          }
+        },
+        "npm-bundled": {
+          "version": "1.0.6",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "npm-packlist": {
+          "version": "1.4.1",
+          "bundled": true,
+          "dev": true,
+          "optional": true,
+          "requires": {
+            "ignore-walk": "3.0.1",
+            "npm-bundled": "1.0.6"
           }
         },
         "npmlog": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.0.tgz",
-          "integrity": "sha512-ocolIkZYZt8UveuiDS0yAkkIjid1o7lPG8cYm05yNYzBn8ykQtaiPMEGp8fY9tKdDgm8okpdKzkvu1y9hUYugA==",
+          "version": "4.1.2",
+          "bundled": true,
           "dev": true,
           "optional": true,
           "requires": {
-            "are-we-there-yet": "1.1.4",
+            "are-we-there-yet": "1.1.5",
             "console-control-strings": "1.1.0",
             "gauge": "2.7.4",
             "set-blocking": "2.0.0"
@@ -5495,28 +4801,18 @@
         },
         "number-is-nan": {
           "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
-          "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
+          "bundled": true,
           "dev": true
         },
-        "oauth-sign": {
-          "version": "0.8.2",
-          "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
-          "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
-          "dev": true,
-          "optional": true
-        },
         "object-assign": {
           "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-          "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
+          "bundled": true,
           "dev": true,
           "optional": true
         },
         "once": {
           "version": "1.4.0",
-          "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-          "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+          "bundled": true,
           "dev": true,
           "requires": {
             "wrappy": "1.0.2"
@@ -5524,22 +4820,19 @@
         },
         "os-homedir": {
           "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
-          "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+          "bundled": true,
           "dev": true,
           "optional": 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=",
+          "bundled": true,
           "dev": true,
           "optional": true
         },
         "osenv": {
-          "version": "0.1.4",
-          "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz",
-          "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=",
+          "version": "0.1.5",
+          "bundled": true,
           "dev": true,
           "optional": true,
           "requires": {
@@ -5549,182 +4842,98 @@
         },
         "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=",
-          "dev": true
-        },
-        "performance-now": {
-          "version": "0.2.0",
-          "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz",
-          "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=",
+          "bundled": true,
           "dev": true,
           "optional": true
         },
         "process-nextick-args": {
-          "version": "1.0.7",
-          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
-          "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
-          "dev": true
-        },
-        "punycode": {
-          "version": "1.4.1",
-          "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
-          "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
-          "dev": true,
-          "optional": true
-        },
-        "qs": {
-          "version": "6.4.0",
-          "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz",
-          "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=",
+          "version": "2.0.0",
+          "bundled": true,
           "dev": true,
           "optional": true
         },
         "rc": {
-          "version": "1.2.1",
-          "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.1.tgz",
-          "integrity": "sha1-LgPo5C7kULjLPc5lvhv4l04d/ZU=",
+          "version": "1.2.8",
+          "bundled": true,
           "dev": true,
           "optional": true,
           "requires": {
-            "deep-extend": "0.4.2",
-            "ini": "1.3.4",
+            "deep-extend": "0.6.0",
+            "ini": "1.3.5",
             "minimist": "1.2.0",
             "strip-json-comments": "2.0.1"
           },
           "dependencies": {
             "minimist": {
               "version": "1.2.0",
-              "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-              "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+              "bundled": true,
               "dev": true,
               "optional": true
             }
           }
         },
         "readable-stream": {
-          "version": "2.2.9",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.9.tgz",
-          "integrity": "sha1-z3jsb0ptHrQ9JkiMrJfwQudLf8g=",
-          "dev": true,
-          "requires": {
-            "buffer-shims": "1.0.0",
-            "core-util-is": "1.0.2",
-            "inherits": "2.0.3",
-            "isarray": "1.0.0",
-            "process-nextick-args": "1.0.7",
-            "string_decoder": "1.0.1",
-            "util-deprecate": "1.0.2"
-          }
-        },
-        "request": {
-          "version": "2.81.0",
-          "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz",
-          "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=",
+          "version": "2.3.6",
+          "bundled": true,
           "dev": true,
           "optional": true,
           "requires": {
-            "aws-sign2": "0.6.0",
-            "aws4": "1.6.0",
-            "caseless": "0.12.0",
-            "combined-stream": "1.0.5",
-            "extend": "3.0.1",
-            "forever-agent": "0.6.1",
-            "form-data": "2.1.4",
-            "har-validator": "4.2.1",
-            "hawk": "3.1.3",
-            "http-signature": "1.1.1",
-            "is-typedarray": "1.0.0",
-            "isstream": "0.1.2",
-            "json-stringify-safe": "5.0.1",
-            "mime-types": "2.1.15",
-            "oauth-sign": "0.8.2",
-            "performance-now": "0.2.0",
-            "qs": "6.4.0",
-            "safe-buffer": "5.0.1",
-            "stringstream": "0.0.5",
-            "tough-cookie": "2.3.2",
-            "tunnel-agent": "0.6.0",
-            "uuid": "3.0.1"
+            "core-util-is": "1.0.2",
+            "inherits": "2.0.3",
+            "isarray": "1.0.0",
+            "process-nextick-args": "2.0.0",
+            "safe-buffer": "5.1.2",
+            "string_decoder": "1.1.1",
+            "util-deprecate": "1.0.2"
           }
         },
         "rimraf": {
-          "version": "2.6.1",
-          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.1.tgz",
-          "integrity": "sha1-wjOOxkPfeht/5cVPqG9XQopV8z0=",
+          "version": "2.6.3",
+          "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
-            "glob": "7.1.2"
+            "glob": "7.1.3"
           }
         },
         "safe-buffer": {
-          "version": "5.0.1",
-          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz",
-          "integrity": "sha1-0mPKVGls2KMGtcplUekt5XkY++c=",
+          "version": "5.1.2",
+          "bundled": true,
           "dev": true
         },
+        "safer-buffer": {
+          "version": "2.1.2",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
+        "sax": {
+          "version": "1.2.4",
+          "bundled": true,
+          "dev": true,
+          "optional": true
+        },
         "semver": {
-          "version": "5.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
-          "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
+          "version": "5.7.0",
+          "bundled": true,
           "dev": true,
           "optional": true
         },
         "set-blocking": {
           "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
-          "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
+          "bundled": true,
           "dev": true,
           "optional": true
         },
         "signal-exit": {
           "version": "3.0.2",
-          "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
-          "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
+          "bundled": true,
           "dev": true,
           "optional": true
         },
-        "sntp": {
-          "version": "1.0.9",
-          "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
-          "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "hoek": "2.16.3"
-          }
-        },
-        "sshpk": {
-          "version": "1.13.0",
-          "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.0.tgz",
-          "integrity": "sha1-/yo+T9BEl1Vf7Zezmg/YL6+zozw=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "asn1": "0.2.3",
-            "assert-plus": "1.0.0",
-            "bcrypt-pbkdf": "1.0.1",
-            "dashdash": "1.14.1",
-            "ecc-jsbn": "0.1.1",
-            "getpass": "0.1.7",
-            "jodid25519": "1.0.2",
-            "jsbn": "0.1.1",
-            "tweetnacl": "0.14.5"
-          },
-          "dependencies": {
-            "assert-plus": {
-              "version": "1.0.0",
-              "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
-              "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
-              "dev": true,
-              "optional": true
-            }
-          }
-        },
         "string-width": {
           "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
-          "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
+          "bundled": true,
           "dev": true,
           "requires": {
             "code-point-at": "1.1.0",
@@ -5733,25 +4942,17 @@
           }
         },
         "string_decoder": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.1.tgz",
-          "integrity": "sha1-YuIA8DmVWmgQ2N8KM//A8BNmLZg=",
+          "version": "1.1.1",
+          "bundled": true,
           "dev": true,
+          "optional": true,
           "requires": {
-            "safe-buffer": "5.0.1"
+            "safe-buffer": "5.1.2"
           }
         },
-        "stringstream": {
-          "version": "0.0.5",
-          "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
-          "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=",
-          "dev": true,
-          "optional": true
-        },
         "strip-ansi": {
           "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
-          "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+          "bundled": true,
           "dev": true,
           "requires": {
             "ansi-regex": "2.1.1"
@@ -5759,100 +4960,34 @@
         },
         "strip-json-comments": {
           "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
-          "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
+          "bundled": true,
           "dev": true,
           "optional": true
         },
         "tar": {
-          "version": "2.2.1",
-          "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz",
-          "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=",
-          "dev": true,
-          "requires": {
-            "block-stream": "0.0.9",
-            "fstream": "1.0.11",
-            "inherits": "2.0.3"
-          }
-        },
-        "tar-pack": {
-          "version": "3.4.0",
-          "resolved": "https://registry.npmjs.org/tar-pack/-/tar-pack-3.4.0.tgz",
-          "integrity": "sha1-I74tf2cagzk3bL2wuP4/3r8xeYQ=",
+          "version": "4.4.8",
+          "bundled": true,
           "dev": true,
           "optional": true,
           "requires": {
-            "debug": "2.6.8",
-            "fstream": "1.0.11",
-            "fstream-ignore": "1.0.5",
-            "once": "1.4.0",
-            "readable-stream": "2.2.9",
-            "rimraf": "2.6.1",
-            "tar": "2.2.1",
-            "uid-number": "0.0.6"
+            "chownr": "1.1.1",
+            "fs-minipass": "1.2.5",
+            "minipass": "2.3.5",
+            "minizlib": "1.2.1",
+            "mkdirp": "0.5.1",
+            "safe-buffer": "5.1.2",
+            "yallist": "3.0.3"
           }
         },
-        "tough-cookie": {
-          "version": "2.3.2",
-          "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz",
-          "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "punycode": "1.4.1"
-          }
-        },
-        "tunnel-agent": {
-          "version": "0.6.0",
-          "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
-          "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "safe-buffer": "5.0.1"
-          }
-        },
-        "tweetnacl": {
-          "version": "0.14.5",
-          "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
-          "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
-          "dev": true,
-          "optional": true
-        },
-        "uid-number": {
-          "version": "0.0.6",
-          "resolved": "https://registry.npmjs.org/uid-number/-/uid-number-0.0.6.tgz",
-          "integrity": "sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=",
-          "dev": true,
-          "optional": 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
-        },
-        "uuid": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz",
-          "integrity": "sha1-ZUS7ot/ajBzxfmKaOjBeK7H+5sE=",
+          "bundled": true,
           "dev": true,
           "optional": true
         },
-        "verror": {
-          "version": "1.3.6",
-          "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz",
-          "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "extsprintf": "1.0.2"
-          }
-        },
         "wide-align": {
-          "version": "1.1.2",
-          "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz",
-          "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==",
+          "version": "1.1.3",
+          "bundled": true,
           "dev": true,
           "optional": true,
           "requires": {
@@ -5861,8 +4996,12 @@
         },
         "wrappy": {
           "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-          "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+          "bundled": true,
+          "dev": true
+        },
+        "yallist": {
+          "version": "3.0.3",
+          "bundled": true,
           "dev": true
         }
       }
@@ -6007,20 +5146,6 @@
       "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
       "dev": true
     },
-    "globby": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
-      "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
-      "dev": true,
-      "requires": {
-        "array-union": "1.0.2",
-        "arrify": "1.0.1",
-        "glob": "7.1.2",
-        "object-assign": "4.1.1",
-        "pify": "2.3.0",
-        "pinkie-promise": "2.0.1"
-      }
-    },
     "globule": {
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.0.tgz",
@@ -6043,10 +5168,23 @@
       "resolved": "https://registry.npmjs.org/guacamole-common-js/-/guacamole-common-js-1.0.0-b.tgz",
       "integrity": "sha512-DLEy7yBQvwwJ4xoWfj1Z+DLOKCy5zwW4ELdpDeYKVWZMpBegbGGwI5qWb61b3aT7KBWsF6DRJHviPlcFHUdMRA=="
     },
-    "hammerjs": {
-      "version": "2.0.8",
-      "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz",
-      "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE="
+    "gzip-size": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz",
+      "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==",
+      "dev": true,
+      "requires": {
+        "duplexer": "0.1.1",
+        "pify": "4.0.1"
+      },
+      "dependencies": {
+        "pify": {
+          "version": "4.0.1",
+          "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz",
+          "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==",
+          "dev": true
+        }
+      }
     },
     "handle-thing": {
       "version": "2.0.0",
@@ -6085,6 +5223,7 @@
       "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
       "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
       "dev": true,
+      "optional": true,
       "requires": {
         "ajv": "5.2.3",
         "har-schema": "2.0.0"
@@ -6095,6 +5234,7 @@
           "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.3.tgz",
           "integrity": "sha1-wG9Zh3jETGsWGrr+NGa4GtGBTtI=",
           "dev": true,
+          "optional": true,
           "requires": {
             "co": "4.6.0",
             "fast-deep-equal": "1.0.0",
@@ -6113,29 +5253,6 @@
         "ansi-regex": "2.1.1"
       }
     },
-    "has-binary": {
-      "version": "0.1.7",
-      "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.7.tgz",
-      "integrity": "sha1-aOYesWIQyVRaClzOBqhzkS/h5ow=",
-      "dev": true,
-      "requires": {
-        "isarray": "0.0.1"
-      },
-      "dependencies": {
-        "isarray": {
-          "version": "0.0.1",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
-          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
-          "dev": true
-        }
-      }
-    },
-    "has-cors": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz",
-      "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=",
-      "dev": true
-    },
     "has-flag": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
@@ -6233,6 +5350,7 @@
       "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz",
       "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==",
       "dev": true,
+      "optional": true,
       "requires": {
         "boom": "4.3.1",
         "cryptiles": "3.1.2",
@@ -6257,6 +5375,12 @@
       "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==",
       "dev": true
     },
+    "hoopy": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz",
+      "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==",
+      "dev": true
+    },
     "hosted-git-info": {
       "version": "2.5.0",
       "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz",
@@ -6685,17 +5809,6 @@
       "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
       "dev": true
     },
-    "https-proxy-agent": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz",
-      "integrity": "sha1-NffabEjOTdv6JkiRrFk+5f+GceY=",
-      "dev": true,
-      "requires": {
-        "agent-base": "2.1.1",
-        "debug": "2.6.9",
-        "extend": "3.0.1"
-      }
-    },
     "humanize-ms": {
       "version": "1.2.1",
       "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
@@ -6876,12 +5989,6 @@
       "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
       "dev": true
     },
-    "ini": {
-      "version": "1.3.4",
-      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz",
-      "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=",
-      "dev": true
-    },
     "inquirer": {
       "version": "6.2.1",
       "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.2.1.tgz",
@@ -7247,12 +6354,6 @@
       "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
       "dev": true
     },
-    "isbinaryfile": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz",
-      "integrity": "sha1-Sj6XTsDLqQBNP8bN5yCeppNopiE=",
-      "dev": true
-    },
     "isexe": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -7335,25 +6436,6 @@
         }
       }
     },
-    "istanbul-api": {
-      "version": "1.1.14",
-      "resolved": "https://registry.npmjs.org/istanbul-api/-/istanbul-api-1.1.14.tgz",
-      "integrity": "sha1-JbxXAffGgMD//5E95G42GaOm5oA=",
-      "dev": true,
-      "requires": {
-        "async": "2.5.0",
-        "fileset": "2.0.3",
-        "istanbul-lib-coverage": "1.1.1",
-        "istanbul-lib-hook": "1.0.7",
-        "istanbul-lib-instrument": "1.8.0",
-        "istanbul-lib-report": "1.1.1",
-        "istanbul-lib-source-maps": "1.2.1",
-        "istanbul-reports": "1.1.2",
-        "js-yaml": "3.7.0",
-        "mkdirp": "0.5.1",
-        "once": "1.4.0"
-      }
-    },
     "istanbul-instrumenter-loader": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-3.0.1.tgz",
@@ -7395,15 +6477,6 @@
       "integrity": "sha512-0+1vDkmzxqJIn5rcoEqapSB4DmPxE31EtI2dF2aCkV5esN9EWHxZ0dwgDClivMXJqE7zaYQxq30hj5L0nlTN5Q==",
       "dev": true
     },
-    "istanbul-lib-hook": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-1.0.7.tgz",
-      "integrity": "sha512-3U2HB9y1ZV9UmFlE12Fx+nPtFqIymzrqCksrXujm3NVbAZIJg/RfYgO1XiIa0mbmxTjWpVEVlkIZJ25xVIAfkQ==",
-      "dev": true,
-      "requires": {
-        "append-transform": "0.4.0"
-      }
-    },
     "istanbul-lib-instrument": {
       "version": "1.8.0",
       "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.8.0.tgz",
@@ -7419,187 +6492,6 @@
         "semver": "5.4.1"
       }
     },
-    "istanbul-lib-report": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz",
-      "integrity": "sha512-tvF+YmCmH4thnez6JFX06ujIA19WPa9YUiwjc1uALF2cv5dmE3It8b5I8Ob7FHJ70H9Y5yF+TDkVa/mcADuw1Q==",
-      "dev": true,
-      "requires": {
-        "istanbul-lib-coverage": "1.1.1",
-        "mkdirp": "0.5.1",
-        "path-parse": "1.0.5",
-        "supports-color": "3.2.3"
-      }
-    },
-    "istanbul-lib-source-maps": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.1.tgz",
-      "integrity": "sha512-mukVvSXCn9JQvdJl8wP/iPhqig0MRtuWuD4ZNKo6vB2Ik//AmhAKe3QnPN02dmkRe3lTudFk3rzoHhwU4hb94w==",
-      "dev": true,
-      "requires": {
-        "debug": "2.6.9",
-        "istanbul-lib-coverage": "1.1.1",
-        "mkdirp": "0.5.1",
-        "rimraf": "2.6.2",
-        "source-map": "0.5.7"
-      }
-    },
-    "istanbul-reports": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-1.1.2.tgz",
-      "integrity": "sha1-D7Lj9qqZIr085F0F2KtNXo4HvU8=",
-      "dev": true,
-      "requires": {
-        "handlebars": "4.0.10"
-      },
-      "dependencies": {
-        "async": {
-          "version": "1.5.2",
-          "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
-          "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
-          "dev": true
-        },
-        "camelcase": {
-          "version": "1.2.1",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
-          "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
-          "dev": true,
-          "optional": true
-        },
-        "cliui": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
-          "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "center-align": "0.1.3",
-            "right-align": "0.1.3",
-            "wordwrap": "0.0.2"
-          },
-          "dependencies": {
-            "wordwrap": {
-              "version": "0.0.2",
-              "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
-              "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
-              "dev": true,
-              "optional": true
-            }
-          }
-        },
-        "handlebars": {
-          "version": "4.0.10",
-          "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz",
-          "integrity": "sha1-PTDHGLCaPZbyPqTMH0A8TTup/08=",
-          "dev": true,
-          "requires": {
-            "async": "1.5.2",
-            "optimist": "0.6.1",
-            "source-map": "0.4.4",
-            "uglify-js": "2.8.29"
-          }
-        },
-        "minimist": {
-          "version": "0.0.10",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
-          "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
-          "dev": true
-        },
-        "optimist": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
-          "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
-          "dev": true,
-          "requires": {
-            "minimist": "0.0.10",
-            "wordwrap": "0.0.3"
-          }
-        },
-        "source-map": {
-          "version": "0.4.4",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
-          "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
-          "dev": true,
-          "requires": {
-            "amdefine": "1.0.1"
-          }
-        },
-        "uglify-js": {
-          "version": "2.8.29",
-          "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
-          "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "source-map": "0.5.7",
-            "uglify-to-browserify": "1.0.2",
-            "yargs": "3.10.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,
-              "optional": true
-            }
-          }
-        },
-        "yargs": {
-          "version": "3.10.0",
-          "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
-          "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "camelcase": "1.2.1",
-            "cliui": "2.1.0",
-            "decamelize": "1.2.0",
-            "window-size": "0.1.0"
-          }
-        }
-      }
-    },
-    "jasmine": {
-      "version": "2.8.0",
-      "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz",
-      "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=",
-      "dev": true,
-      "requires": {
-        "exit": "0.1.2",
-        "glob": "7.1.2",
-        "jasmine-core": "2.8.0"
-      },
-      "dependencies": {
-        "jasmine-core": {
-          "version": "2.8.0",
-          "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz",
-          "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=",
-          "dev": true
-        }
-      }
-    },
-    "jasmine-core": {
-      "version": "2.5.2",
-      "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.5.2.tgz",
-      "integrity": "sha1-b2G9eQYeJ/Q+b5NV5Es8bKtv8pc=",
-      "dev": true
-    },
-    "jasmine-spec-reporter": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-3.2.0.tgz",
-      "integrity": "sha1-/b6FqAzN07J2dGvHf96Dwc53Pv8=",
-      "dev": true,
-      "requires": {
-        "colors": "1.1.2"
-      }
-    },
-    "jasminewd2": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz",
-      "integrity": "sha1-43zwsX8ZnM4jvqcbIDk5Uka07E4=",
-      "dev": true
-    },
     "js-base64": {
       "version": "2.3.2",
       "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.3.2.tgz",
@@ -7629,12 +6521,6 @@
       "dev": true,
       "optional": true
     },
-    "jsesc": {
-      "version": "0.5.0",
-      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
-      "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
-      "dev": true
-    },
     "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",
@@ -7658,6 +6544,7 @@
       "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
       "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
       "dev": true,
+      "optional": true,
       "requires": {
         "jsonify": "0.0.0"
       }
@@ -7687,7 +6574,8 @@
       "version": "0.0.0",
       "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
       "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
-      "dev": true
+      "dev": true,
+      "optional": true
     },
     "jsonparse": {
       "version": "1.3.1",
@@ -7707,117 +6595,6 @@
         "verror": "1.10.0"
       }
     },
-    "karma": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/karma/-/karma-1.4.1.tgz",
-      "integrity": "sha1-QZgacdVCN2BrCj6oxYyQdz9BZQ4=",
-      "dev": true,
-      "requires": {
-        "bluebird": "3.5.1",
-        "body-parser": "1.18.2",
-        "chokidar": "1.7.0",
-        "colors": "1.1.2",
-        "combine-lists": "1.0.1",
-        "connect": "3.6.5",
-        "core-js": "2.4.1",
-        "di": "0.0.1",
-        "dom-serialize": "2.2.1",
-        "expand-braces": "0.1.2",
-        "glob": "7.1.2",
-        "graceful-fs": "4.1.11",
-        "http-proxy": "1.16.2",
-        "isbinaryfile": "3.0.2",
-        "lodash": "3.10.1",
-        "log4js": "0.6.38",
-        "mime": "1.4.1",
-        "minimatch": "3.0.4",
-        "optimist": "0.6.1",
-        "qjobs": "1.1.5",
-        "range-parser": "1.2.0",
-        "rimraf": "2.6.2",
-        "safe-buffer": "5.1.1",
-        "socket.io": "1.7.2",
-        "source-map": "0.5.7",
-        "tmp": "0.0.28",
-        "useragent": "2.2.1"
-      },
-      "dependencies": {
-        "lodash": {
-          "version": "3.10.1",
-          "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz",
-          "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=",
-          "dev": true
-        },
-        "minimist": {
-          "version": "0.0.10",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
-          "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
-          "dev": true
-        },
-        "optimist": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
-          "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
-          "dev": true,
-          "requires": {
-            "minimist": "0.0.10",
-            "wordwrap": "0.0.3"
-          }
-        },
-        "tmp": {
-          "version": "0.0.28",
-          "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.28.tgz",
-          "integrity": "sha1-Fyc1t/YU6nrzlmT6hM8N5OUV0SA=",
-          "dev": true,
-          "requires": {
-            "os-tmpdir": "1.0.2"
-          }
-        }
-      }
-    },
-    "karma-chrome-launcher": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-2.0.0.tgz",
-      "integrity": "sha1-wnkMWjKxVXfQ//Wk1aJwOztDnCU=",
-      "dev": true,
-      "requires": {
-        "fs-access": "1.0.1",
-        "which": "1.3.0"
-      }
-    },
-    "karma-cli": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/karma-cli/-/karma-cli-1.0.1.tgz",
-      "integrity": "sha1-rmw8WKMTodALRRZMRVubhs4X+WA=",
-      "dev": true,
-      "requires": {
-        "resolve": "1.4.0"
-      }
-    },
-    "karma-coverage-istanbul-reporter": {
-      "version": "0.2.3",
-      "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-0.2.3.tgz",
-      "integrity": "sha1-EfG+nPqTdVp3usOasW4xWnEAtcU=",
-      "dev": true,
-      "requires": {
-        "istanbul-api": "1.1.14"
-      }
-    },
-    "karma-jasmine": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-1.1.0.tgz",
-      "integrity": "sha1-IuTAa/mhguUpTR9wXjczgRuBCs8=",
-      "dev": true
-    },
-    "karma-jasmine-html-reporter": {
-      "version": "0.2.2",
-      "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-0.2.2.tgz",
-      "integrity": "sha1-SKjl7xiAdhfuK14zwRlMNbQ5Ukw=",
-      "dev": true,
-      "requires": {
-        "karma-jasmine": "1.1.0"
-      }
-    },
     "karma-source-map-support": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.3.0.tgz",
@@ -7860,13 +6637,6 @@
         "is-buffer": "1.1.5"
       }
     },
-    "lazy-cache": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
-      "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
-      "dev": true,
-      "optional": true
-    },
     "lcid": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
@@ -8025,60 +6795,12 @@
       "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=",
       "dev": true
     },
-    "log4js": {
-      "version": "0.6.38",
-      "resolved": "https://registry.npmjs.org/log4js/-/log4js-0.6.38.tgz",
-      "integrity": "sha1-LElBFmldb7JUgJQ9P8hy5mKlIv0=",
-      "dev": true,
-      "requires": {
-        "readable-stream": "1.0.34",
-        "semver": "4.3.6"
-      },
-      "dependencies": {
-        "isarray": {
-          "version": "0.0.1",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
-          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
-          "dev": true
-        },
-        "readable-stream": {
-          "version": "1.0.34",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
-          "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
-          "dev": true,
-          "requires": {
-            "core-util-is": "1.0.2",
-            "inherits": "2.0.3",
-            "isarray": "0.0.1",
-            "string_decoder": "0.10.31"
-          }
-        },
-        "semver": {
-          "version": "4.3.6",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz",
-          "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=",
-          "dev": true
-        },
-        "string_decoder": {
-          "version": "0.10.31",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
-          "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
-          "dev": true
-        }
-      }
-    },
     "loglevel": {
       "version": "1.6.1",
       "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz",
       "integrity": "sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=",
       "dev": true
     },
-    "longest": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
-      "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
-      "dev": true
-    },
     "loose-envify": {
       "version": "1.3.1",
       "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz",
@@ -8570,9 +7292,9 @@
       "dev": true
     },
     "nan": {
-      "version": "2.7.0",
-      "resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz",
-      "integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=",
+      "version": "2.14.0",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
+      "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
       "dev": true,
       "optional": true
     },
@@ -8635,16 +7357,6 @@
         "date-fns": "1.30.1"
       }
     },
-    "ng2-toastr": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/ng2-toastr/-/ng2-toastr-4.1.2.tgz",
-      "integrity": "sha1-G0UvBxOZYcOPhmxuJKBiR++iGxE="
-    },
-    "ngx-mat-daterange-picker": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/ngx-mat-daterange-picker/-/ngx-mat-daterange-picker-1.1.4.tgz",
-      "integrity": "sha512-bfIYGJicxwg58j6LZjUE5JPXqq7yJfremFhX5S/DnUYwQjgmDWN6PUOFEegEO7ua4QdgGWrhK04ElOw25aWrzQ=="
-    },
     "ngx-toastr": {
       "version": "9.1.2",
       "resolved": "https://registry.npmjs.org/ngx-toastr/-/ngx-toastr-9.1.2.tgz",
@@ -9075,12 +7787,6 @@
         "set-blocking": "2.0.0"
       }
     },
-    "null-check": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/null-check/-/null-check-1.0.0.tgz",
-      "integrity": "sha1-l33/1xdgErnsMNKjnbXPcqBDnt0=",
-      "dev": true
-    },
     "num2fraction": {
       "version": "1.2.2",
       "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
@@ -9097,7 +7803,8 @@
       "version": "0.8.2",
       "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
       "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=",
-      "dev": true
+      "dev": true,
+      "optional": true
     },
     "object-assign": {
       "version": "4.1.1",
@@ -9105,12 +7812,6 @@
       "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
       "dev": true
     },
-    "object-component": {
-      "version": "0.0.3",
-      "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz",
-      "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=",
-      "dev": true
-    },
     "object-copy": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
@@ -9216,6 +7917,12 @@
         "mimic-fn": "1.2.0"
       }
     },
+    "opener": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz",
+      "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==",
+      "dev": true
+    },
     "opn": {
       "version": "5.4.0",
       "resolved": "https://registry.npmjs.org/opn/-/opn-5.4.0.tgz",
@@ -9265,12 +7972,6 @@
         }
       }
     },
-    "options": {
-      "version": "0.0.6",
-      "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz",
-      "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=",
-      "dev": true
-    },
     "original": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz",
@@ -9541,33 +8242,6 @@
       "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==",
       "dev": true
     },
-    "parsejson": {
-      "version": "0.0.3",
-      "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.3.tgz",
-      "integrity": "sha1-q343WfIJ7OmUN5c/fQ8fZK4OZKs=",
-      "dev": true,
-      "requires": {
-        "better-assert": "1.0.2"
-      }
-    },
-    "parseqs": {
-      "version": "0.0.5",
-      "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz",
-      "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
-      "dev": true,
-      "requires": {
-        "better-assert": "1.0.2"
-      }
-    },
-    "parseuri": {
-      "version": "0.0.5",
-      "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz",
-      "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
-      "dev": true,
-      "requires": {
-        "better-assert": "1.0.2"
-      }
-    },
     "parseurl": {
       "version": "1.3.2",
       "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
@@ -9891,80 +8565,6 @@
         "genfun": "5.0.0"
       }
     },
-    "protractor": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/protractor/-/protractor-5.1.2.tgz",
-      "integrity": "sha1-myIXQXCaTGLVzVPGqt1UpxE36V8=",
-      "dev": true,
-      "requires": {
-        "@types/node": "6.0.89",
-        "@types/q": "0.0.32",
-        "@types/selenium-webdriver": "2.53.42",
-        "blocking-proxy": "0.0.5",
-        "chalk": "1.1.3",
-        "glob": "7.1.2",
-        "jasmine": "2.8.0",
-        "jasminewd2": "2.2.0",
-        "optimist": "0.6.1",
-        "q": "1.4.1",
-        "saucelabs": "1.3.0",
-        "selenium-webdriver": "3.0.1",
-        "source-map-support": "0.4.18",
-        "webdriver-js-extender": "1.0.0",
-        "webdriver-manager": "12.0.6"
-      },
-      "dependencies": {
-        "minimist": {
-          "version": "0.0.10",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
-          "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
-          "dev": true
-        },
-        "optimist": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
-          "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
-          "dev": true,
-          "requires": {
-            "minimist": "0.0.10",
-            "wordwrap": "0.0.3"
-          }
-        },
-        "q": {
-          "version": "1.4.1",
-          "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz",
-          "integrity": "sha1-VXBbzZPF82c1MMLCy8DCs63cKG4=",
-          "dev": true
-        },
-        "webdriver-manager": {
-          "version": "12.0.6",
-          "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.0.6.tgz",
-          "integrity": "sha1-PfGkgZdwELTL+MnYXHpXeCjA5ws=",
-          "dev": true,
-          "requires": {
-            "adm-zip": "0.4.7",
-            "chalk": "1.1.3",
-            "del": "2.2.2",
-            "glob": "7.1.2",
-            "ini": "1.3.4",
-            "minimist": "1.2.0",
-            "q": "1.4.1",
-            "request": "2.83.0",
-            "rimraf": "2.6.2",
-            "semver": "5.4.1",
-            "xml2js": "0.4.19"
-          },
-          "dependencies": {
-            "minimist": {
-              "version": "1.2.0",
-              "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-              "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
-              "dev": true
-            }
-          }
-        }
-      }
-    },
     "proxy-addr": {
       "version": "2.0.4",
       "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz",
@@ -10054,17 +8654,12 @@
       "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
       "dev": true
     },
-    "qjobs": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.1.5.tgz",
-      "integrity": "sha1-ZZ3p8s+NzCehSBJ28gU3cnI4LnM=",
-      "dev": true
-    },
     "qs": {
       "version": "6.5.1",
       "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
       "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==",
-      "dev": true
+      "dev": true,
+      "optional": true
     },
     "querystring": {
       "version": "0.2.0",
@@ -10150,18 +8745,6 @@
       "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=",
       "dev": true
     },
-    "raw-body": {
-      "version": "2.3.2",
-      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz",
-      "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=",
-      "dev": true,
-      "requires": {
-        "bytes": "3.0.0",
-        "http-errors": "1.6.2",
-        "iconv-lite": "0.4.19",
-        "unpipe": "1.0.0"
-      }
-    },
     "raw-loader": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-1.0.0.tgz",
@@ -10254,12 +8837,6 @@
       "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==",
       "dev": true
     },
-    "regenerate": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz",
-      "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==",
-      "dev": true
-    },
     "regenerator-runtime": {
       "version": "0.11.0",
       "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz",
@@ -10285,32 +8862,6 @@
         "safe-regex": "1.1.0"
       }
     },
-    "regexpu-core": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz",
-      "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=",
-      "dev": true,
-      "requires": {
-        "regenerate": "1.4.0",
-        "regjsgen": "0.2.0",
-        "regjsparser": "0.1.5"
-      }
-    },
-    "regjsgen": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
-      "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=",
-      "dev": true
-    },
-    "regjsparser": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
-      "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=",
-      "dev": true,
-      "requires": {
-        "jsesc": "0.5.0"
-      }
-    },
     "remove-trailing-separator": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
@@ -10343,6 +8894,7 @@
       "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz",
       "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==",
       "dev": true,
+      "optional": true,
       "requires": {
         "aws-sign2": "0.7.0",
         "aws4": "1.6.0",
@@ -10444,16 +8996,6 @@
       "integrity": "sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q=",
       "dev": true
     },
-    "right-align": {
-      "version": "0.1.3",
-      "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
-      "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "align-text": "0.1.4"
-      }
-    },
     "rimraf": {
       "version": "2.6.2",
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
@@ -10565,21 +9107,6 @@
         }
       }
     },
-    "saucelabs": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.3.0.tgz",
-      "integrity": "sha1-0kDoAJ33+ocwbsRXimm6O1xCT+4=",
-      "dev": true,
-      "requires": {
-        "https-proxy-agent": "1.0.0"
-      }
-    },
-    "sax": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
-      "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
-      "dev": true
-    },
     "schema-utils": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz",
@@ -10618,29 +9145,6 @@
       "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=",
       "dev": true
     },
-    "selenium-webdriver": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.0.1.tgz",
-      "integrity": "sha1-ot6l2kqX9mcuiefKcnbO+jZRR6c=",
-      "dev": true,
-      "requires": {
-        "adm-zip": "0.4.7",
-        "rimraf": "2.6.2",
-        "tmp": "0.0.30",
-        "xml2js": "0.4.19"
-      },
-      "dependencies": {
-        "tmp": {
-          "version": "0.0.30",
-          "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz",
-          "integrity": "sha1-ckGdSovn1s51FI/YsyTlk6cRwu0=",
-          "dev": true,
-          "requires": {
-            "os-tmpdir": "1.0.2"
-          }
-        }
-      }
-    },
     "selfsigned": {
       "version": "1.10.4",
       "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.4.tgz",
@@ -10656,15 +9160,6 @@
       "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==",
       "dev": true
     },
-    "semver-dsl": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/semver-dsl/-/semver-dsl-1.0.1.tgz",
-      "integrity": "sha1-02eN5VVeimH2Ke7QJTZq5fJzQKA=",
-      "dev": true,
-      "requires": {
-        "semver": "5.4.1"
-      }
-    },
     "semver-intersect": {
       "version": "1.4.0",
       "resolved": "https://registry.npmjs.org/semver-intersect/-/semver-intersect-1.4.0.tgz",
@@ -10989,152 +9484,11 @@
       "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz",
       "integrity": "sha1-UGQRDwr4X3z9t9a2ekACjOUrSys=",
       "dev": true,
+      "optional": true,
       "requires": {
         "hoek": "4.2.0"
       }
     },
-    "socket.io": {
-      "version": "1.7.2",
-      "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.7.2.tgz",
-      "integrity": "sha1-g7u98ueSY7N4kA2kA+eEPgXcO3E=",
-      "dev": true,
-      "requires": {
-        "debug": "2.3.3",
-        "engine.io": "1.8.2",
-        "has-binary": "0.1.7",
-        "object-assign": "4.1.0",
-        "socket.io-adapter": "0.5.0",
-        "socket.io-client": "1.7.2",
-        "socket.io-parser": "2.3.1"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "2.3.3",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
-          "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
-          "dev": true,
-          "requires": {
-            "ms": "0.7.2"
-          }
-        },
-        "ms": {
-          "version": "0.7.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
-          "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
-          "dev": true
-        },
-        "object-assign": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz",
-          "integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=",
-          "dev": true
-        }
-      }
-    },
-    "socket.io-adapter": {
-      "version": "0.5.0",
-      "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.5.0.tgz",
-      "integrity": "sha1-y21LuL7IHhB4uZZ3+c7QBGBmu4s=",
-      "dev": true,
-      "requires": {
-        "debug": "2.3.3",
-        "socket.io-parser": "2.3.1"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "2.3.3",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
-          "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
-          "dev": true,
-          "requires": {
-            "ms": "0.7.2"
-          }
-        },
-        "ms": {
-          "version": "0.7.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
-          "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
-          "dev": true
-        }
-      }
-    },
-    "socket.io-client": {
-      "version": "1.7.2",
-      "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.7.2.tgz",
-      "integrity": "sha1-Of2ww91FDjIbfkDP2DYS7FM91kQ=",
-      "dev": true,
-      "requires": {
-        "backo2": "1.0.2",
-        "component-bind": "1.0.0",
-        "component-emitter": "1.2.1",
-        "debug": "2.3.3",
-        "engine.io-client": "1.8.2",
-        "has-binary": "0.1.7",
-        "indexof": "0.0.1",
-        "object-component": "0.0.3",
-        "parseuri": "0.0.5",
-        "socket.io-parser": "2.3.1",
-        "to-array": "0.1.4"
-      },
-      "dependencies": {
-        "component-emitter": {
-          "version": "1.2.1",
-          "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
-          "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
-          "dev": true
-        },
-        "debug": {
-          "version": "2.3.3",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz",
-          "integrity": "sha1-QMRT5n5uE8kB3ewxeviYbNqe/4w=",
-          "dev": true,
-          "requires": {
-            "ms": "0.7.2"
-          }
-        },
-        "ms": {
-          "version": "0.7.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz",
-          "integrity": "sha1-riXPJRKziFodldfwN4aNhDESR2U=",
-          "dev": true
-        }
-      }
-    },
-    "socket.io-parser": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.3.1.tgz",
-      "integrity": "sha1-3VMgJRA85Clpcya+/WQAX8/ltKA=",
-      "dev": true,
-      "requires": {
-        "component-emitter": "1.1.2",
-        "debug": "2.2.0",
-        "isarray": "0.0.1",
-        "json3": "3.3.2"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "2.2.0",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz",
-          "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=",
-          "dev": true,
-          "requires": {
-            "ms": "0.7.1"
-          }
-        },
-        "isarray": {
-          "version": "0.0.1",
-          "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
-          "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
-          "dev": true
-        },
-        "ms": {
-          "version": "0.7.1",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz",
-          "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=",
-          "dev": true
-        }
-      }
-    },
     "sockjs": {
       "version": "0.3.19",
       "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz",
@@ -11616,7 +9970,8 @@
       "version": "0.0.5",
       "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
       "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=",
-      "dev": true
+      "dev": true,
+      "optional": true
     },
     "strip-ansi": {
       "version": "3.0.1",
@@ -11949,12 +10304,6 @@
         "os-tmpdir": "1.0.2"
       }
     },
-    "to-array": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz",
-      "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=",
-      "dev": true
-    },
     "to-arraybuffer": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
@@ -12014,6 +10363,7 @@
       "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz",
       "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=",
       "dev": true,
+      "optional": true,
       "requires": {
         "punycode": "1.4.1"
       }
@@ -12045,6 +10395,12 @@
         "glob": "7.1.2"
       }
     },
+    "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": "2.0.0",
       "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-2.0.0.tgz",
@@ -12196,16 +10552,6 @@
         "prelude-ls": "1.1.2"
       }
     },
-    "type-is": {
-      "version": "1.6.15",
-      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz",
-      "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=",
-      "dev": true,
-      "requires": {
-        "media-typer": "0.3.0",
-        "mime-types": "2.1.17"
-      }
-    },
     "typedarray": {
       "version": "0.0.6",
       "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
@@ -12238,19 +10584,6 @@
         }
       }
     },
-    "uglify-to-browserify": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
-      "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
-      "dev": true,
-      "optional": true
-    },
-    "ultron": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz",
-      "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=",
-      "dev": true
-    },
     "union-value": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
@@ -12425,24 +10758,6 @@
       "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=",
       "dev": true
     },
-    "useragent": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/useragent/-/useragent-2.2.1.tgz",
-      "integrity": "sha1-z1k+9PLRdYdei7ZY6pLhik/QbY4=",
-      "dev": true,
-      "requires": {
-        "lru-cache": "2.2.4",
-        "tmp": "0.0.33"
-      },
-      "dependencies": {
-        "lru-cache": {
-          "version": "2.2.4",
-          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.2.4.tgz",
-          "integrity": "sha1-bGWGGb7PFAMdDQtZSxYELOTcBj0=",
-          "dev": true
-        }
-      }
-    },
     "util": {
       "version": "0.11.1",
       "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
@@ -12524,12 +10839,6 @@
         "indexof": "0.0.1"
       }
     },
-    "void-elements": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz",
-      "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=",
-      "dev": true
-    },
     "watchpack": {
       "version": "1.6.0",
       "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz",
@@ -12777,24 +11086,28 @@
           "dependencies": {
             "abbrev": {
               "version": "1.1.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+              "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
               "dev": true,
               "optional": true
             },
             "ansi-regex": {
               "version": "2.1.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+              "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
               "dev": true
             },
             "aproba": {
               "version": "1.2.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+              "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
               "dev": true,
               "optional": true
             },
             "are-we-there-yet": {
               "version": "1.1.5",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+              "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -12804,12 +11117,14 @@
             },
             "balanced-match": {
               "version": "1.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+              "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
               "dev": true
             },
             "brace-expansion": {
               "version": "1.1.11",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+              "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
               "dev": true,
               "requires": {
                 "balanced-match": "1.0.0",
@@ -12818,34 +11133,40 @@
             },
             "chownr": {
               "version": "1.1.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
+              "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
               "dev": true,
               "optional": true
             },
             "code-point-at": {
               "version": "1.1.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+              "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
               "dev": true
             },
             "concat-map": {
               "version": "0.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+              "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
               "dev": true
             },
             "console-control-strings": {
               "version": "1.1.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+              "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
               "dev": true
             },
             "core-util-is": {
               "version": "1.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+              "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
               "dev": true,
               "optional": true
             },
             "debug": {
               "version": "2.6.9",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+              "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -12854,25 +11175,29 @@
             },
             "deep-extend": {
               "version": "0.6.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+              "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
               "dev": true,
               "optional": true
             },
             "delegates": {
               "version": "1.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+              "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
               "dev": true,
               "optional": true
             },
             "detect-libc": {
               "version": "1.0.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+              "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
               "dev": true,
               "optional": true
             },
             "fs-minipass": {
               "version": "1.2.5",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
+              "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -12881,13 +11206,15 @@
             },
             "fs.realpath": {
               "version": "1.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+              "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
               "dev": true,
               "optional": true
             },
             "gauge": {
               "version": "2.7.4",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+              "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
               "dev": true,
               "optional": true,
               "requires": {
@@ -12903,7 +11230,8 @@
             },
             "glob": {
               "version": "7.1.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+              "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -12917,13 +11245,15 @@
             },
             "has-unicode": {
               "version": "2.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+              "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
               "dev": true,
               "optional": true
             },
             "iconv-lite": {
               "version": "0.4.24",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+              "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -12932,7 +11262,8 @@
             },
             "ignore-walk": {
               "version": "3.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
+              "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -12941,7 +11272,8 @@
             },
             "inflight": {
               "version": "1.0.6",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+              "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
               "dev": true,
               "optional": true,
               "requires": {
@@ -12951,18 +11283,21 @@
             },
             "inherits": {
               "version": "2.0.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+              "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
               "dev": true
             },
             "ini": {
               "version": "1.3.5",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+              "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
               "dev": true,
               "optional": true
             },
             "is-fullwidth-code-point": {
               "version": "1.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+              "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
               "dev": true,
               "requires": {
                 "number-is-nan": "1.0.1"
@@ -12970,13 +11305,15 @@
             },
             "isarray": {
               "version": "1.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+              "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
               "dev": true,
               "optional": true
             },
             "minimatch": {
               "version": "3.0.4",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+              "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
               "dev": true,
               "requires": {
                 "brace-expansion": "1.1.11"
@@ -12984,12 +11321,14 @@
             },
             "minimist": {
               "version": "0.0.8",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+              "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
               "dev": true
             },
             "minipass": {
               "version": "2.3.5",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
+              "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
               "dev": true,
               "requires": {
                 "safe-buffer": "5.1.2",
@@ -12998,7 +11337,8 @@
             },
             "minizlib": {
               "version": "1.2.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
+              "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -13007,7 +11347,8 @@
             },
             "mkdirp": {
               "version": "0.5.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+              "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
               "dev": true,
               "requires": {
                 "minimist": "0.0.8"
@@ -13015,13 +11356,15 @@
             },
             "ms": {
               "version": "2.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+              "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
               "dev": true,
               "optional": true
             },
             "needle": {
               "version": "2.2.4",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz",
+              "integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -13032,7 +11375,8 @@
             },
             "node-pre-gyp": {
               "version": "0.10.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz",
+              "integrity": "sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -13050,7 +11394,8 @@
             },
             "nopt": {
               "version": "4.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
+              "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
               "dev": true,
               "optional": true,
               "requires": {
@@ -13060,13 +11405,15 @@
             },
             "npm-bundled": {
               "version": "1.0.5",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz",
+              "integrity": "sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g==",
               "dev": true,
               "optional": true
             },
             "npm-packlist": {
               "version": "1.2.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.2.0.tgz",
+              "integrity": "sha512-7Mni4Z8Xkx0/oegoqlcao/JpPCPEMtUvsmB0q7mgvlMinykJLSRTYuFqoQLYgGY8biuxIeiHO+QNJKbCfljewQ==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -13076,7 +11423,8 @@
             },
             "npmlog": {
               "version": "4.1.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+              "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -13088,18 +11436,21 @@
             },
             "number-is-nan": {
               "version": "1.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+              "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
               "dev": true
             },
             "object-assign": {
               "version": "4.1.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+              "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
               "dev": true,
               "optional": true
             },
             "once": {
               "version": "1.4.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+              "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
               "dev": true,
               "requires": {
                 "wrappy": "1.0.2"
@@ -13107,19 +11458,22 @@
             },
             "os-homedir": {
               "version": "1.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+              "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
               "dev": true,
               "optional": true
             },
             "os-tmpdir": {
               "version": "1.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+              "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
               "dev": true,
               "optional": true
             },
             "osenv": {
               "version": "0.1.5",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
+              "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -13129,19 +11483,22 @@
             },
             "path-is-absolute": {
               "version": "1.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+              "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
               "dev": true,
               "optional": true
             },
             "process-nextick-args": {
               "version": "2.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+              "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
               "dev": true,
               "optional": true
             },
             "rc": {
               "version": "1.2.8",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+              "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -13153,7 +11510,8 @@
               "dependencies": {
                 "minimist": {
                   "version": "1.2.0",
-                  "bundled": true,
+                  "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+                  "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
                   "dev": true,
                   "optional": true
                 }
@@ -13161,7 +11519,8 @@
             },
             "readable-stream": {
               "version": "2.3.6",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+              "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -13176,7 +11535,8 @@
             },
             "rimraf": {
               "version": "2.6.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+              "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -13185,42 +11545,49 @@
             },
             "safe-buffer": {
               "version": "5.1.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+              "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
               "dev": true
             },
             "safer-buffer": {
               "version": "2.1.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+              "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
               "dev": true,
               "optional": true
             },
             "sax": {
               "version": "1.2.4",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+              "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
               "dev": true,
               "optional": true
             },
             "semver": {
               "version": "5.6.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
+              "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
               "dev": true,
               "optional": true
             },
             "set-blocking": {
               "version": "2.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+              "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
               "dev": true,
               "optional": true
             },
             "signal-exit": {
               "version": "3.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+              "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
               "dev": true,
               "optional": true
             },
             "string-width": {
               "version": "1.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+              "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
               "dev": true,
               "requires": {
                 "code-point-at": "1.1.0",
@@ -13230,7 +11597,8 @@
             },
             "string_decoder": {
               "version": "1.1.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+              "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -13239,7 +11607,8 @@
             },
             "strip-ansi": {
               "version": "3.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+              "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
               "dev": true,
               "requires": {
                 "ansi-regex": "2.1.1"
@@ -13247,13 +11616,15 @@
             },
             "strip-json-comments": {
               "version": "2.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+              "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
               "dev": true,
               "optional": true
             },
             "tar": {
               "version": "4.4.8",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz",
+              "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -13268,13 +11639,15 @@
             },
             "util-deprecate": {
               "version": "1.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+              "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
               "dev": true,
               "optional": true
             },
             "wide-align": {
               "version": "1.1.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+              "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -13283,12 +11656,14 @@
             },
             "wrappy": {
               "version": "1.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+              "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
               "dev": true
             },
             "yallist": {
               "version": "3.0.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
+              "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
               "dev": true
             }
           }
@@ -13434,59 +11809,6 @@
       "resolved": "https://registry.npmjs.org/web-animations-js/-/web-animations-js-2.3.1.tgz",
       "integrity": "sha1-Om2bwVGWN3qQ+OKAP6UmIWWwRRA="
     },
-    "webdriver-js-extender": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-1.0.0.tgz",
-      "integrity": "sha1-gcUzqeM9W/tZe05j4s2yW1R3dRU=",
-      "dev": true,
-      "requires": {
-        "@types/selenium-webdriver": "2.53.42",
-        "selenium-webdriver": "2.53.3"
-      },
-      "dependencies": {
-        "adm-zip": {
-          "version": "0.4.4",
-          "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.4.tgz",
-          "integrity": "sha1-ph7VrmkFw66lizplfSUDMJEFJzY=",
-          "dev": true
-        },
-        "sax": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/sax/-/sax-0.6.1.tgz",
-          "integrity": "sha1-VjsZx8HeiS4Jv8Ty/DDjwn8JUrk=",
-          "dev": true
-        },
-        "selenium-webdriver": {
-          "version": "2.53.3",
-          "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-2.53.3.tgz",
-          "integrity": "sha1-0p/1qVff8aG0ncRXdW5OS/vc4IU=",
-          "dev": true,
-          "requires": {
-            "adm-zip": "0.4.4",
-            "rimraf": "2.6.2",
-            "tmp": "0.0.24",
-            "ws": "1.1.1",
-            "xml2js": "0.4.4"
-          }
-        },
-        "tmp": {
-          "version": "0.0.24",
-          "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.24.tgz",
-          "integrity": "sha1-1qXhmNFKmDXMby18PZ4wJCjIzxI=",
-          "dev": true
-        },
-        "xml2js": {
-          "version": "0.4.4",
-          "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.4.tgz",
-          "integrity": "sha1-MREBAAMAiuGSQOuhdJe1fHKcVV0=",
-          "dev": true,
-          "requires": {
-            "sax": "0.6.1",
-            "xmlbuilder": "9.0.4"
-          }
-        }
-      }
-    },
     "webpack": {
       "version": "4.29.0",
       "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.29.0.tgz",
@@ -13805,6 +12127,76 @@
         }
       }
     },
+    "webpack-bundle-analyzer": {
+      "version": "3.3.2",
+      "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.3.2.tgz",
+      "integrity": "sha512-7qvJLPKB4rRWZGjVp5U1KEjwutbDHSKboAl0IfafnrdXMrgC0tOtZbQD6Rw0u4cmpgRN4O02Fc0t8eAT+FgGzA==",
+      "dev": true,
+      "requires": {
+        "acorn": "6.0.7",
+        "acorn-walk": "6.1.1",
+        "bfj": "6.1.1",
+        "chalk": "2.4.2",
+        "commander": "2.20.0",
+        "ejs": "2.6.1",
+        "express": "4.16.4",
+        "filesize": "3.6.1",
+        "gzip-size": "5.1.1",
+        "lodash": "4.17.11",
+        "mkdirp": "0.5.1",
+        "opener": "1.5.1",
+        "ws": "6.2.1"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "3.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+          "dev": true,
+          "requires": {
+            "color-convert": "1.9.3"
+          }
+        },
+        "chalk": {
+          "version": "2.4.2",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+          "dev": true,
+          "requires": {
+            "ansi-styles": "3.2.1",
+            "escape-string-regexp": "1.0.5",
+            "supports-color": "5.5.0"
+          }
+        },
+        "commander": {
+          "version": "2.20.0",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
+          "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
+          "dev": true
+        },
+        "has-flag": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+          "dev": true
+        },
+        "lodash": {
+          "version": "4.17.11",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
+          "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "5.5.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+          "dev": true,
+          "requires": {
+            "has-flag": "3.0.0"
+          }
+        }
+      }
+    },
     "webpack-core": {
       "version": "0.6.9",
       "resolved": "https://registry.npmjs.org/webpack-core/-/webpack-core-0.6.9.tgz",
@@ -14246,24 +12638,28 @@
           "dependencies": {
             "abbrev": {
               "version": "1.1.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+              "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
               "dev": true,
               "optional": true
             },
             "ansi-regex": {
               "version": "2.1.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+              "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
               "dev": true
             },
             "aproba": {
               "version": "1.2.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+              "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
               "dev": true,
               "optional": true
             },
             "are-we-there-yet": {
               "version": "1.1.5",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+              "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14273,12 +12669,14 @@
             },
             "balanced-match": {
               "version": "1.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+              "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
               "dev": true
             },
             "brace-expansion": {
               "version": "1.1.11",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+              "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
               "dev": true,
               "requires": {
                 "balanced-match": "1.0.0",
@@ -14287,34 +12685,40 @@
             },
             "chownr": {
               "version": "1.1.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
+              "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
               "dev": true,
               "optional": true
             },
             "code-point-at": {
               "version": "1.1.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+              "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
               "dev": true
             },
             "concat-map": {
               "version": "0.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+              "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
               "dev": true
             },
             "console-control-strings": {
               "version": "1.1.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+              "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
               "dev": true
             },
             "core-util-is": {
               "version": "1.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+              "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
               "dev": true,
               "optional": true
             },
             "debug": {
               "version": "2.6.9",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+              "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14323,25 +12727,29 @@
             },
             "deep-extend": {
               "version": "0.6.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+              "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
               "dev": true,
               "optional": true
             },
             "delegates": {
               "version": "1.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+              "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
               "dev": true,
               "optional": true
             },
             "detect-libc": {
               "version": "1.0.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+              "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
               "dev": true,
               "optional": true
             },
             "fs-minipass": {
               "version": "1.2.5",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
+              "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14350,13 +12758,15 @@
             },
             "fs.realpath": {
               "version": "1.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+              "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
               "dev": true,
               "optional": true
             },
             "gauge": {
               "version": "2.7.4",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+              "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14372,7 +12782,8 @@
             },
             "glob": {
               "version": "7.1.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+              "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14386,13 +12797,15 @@
             },
             "has-unicode": {
               "version": "2.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+              "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
               "dev": true,
               "optional": true
             },
             "iconv-lite": {
               "version": "0.4.24",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+              "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14401,7 +12814,8 @@
             },
             "ignore-walk": {
               "version": "3.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
+              "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14410,7 +12824,8 @@
             },
             "inflight": {
               "version": "1.0.6",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+              "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14420,18 +12835,21 @@
             },
             "inherits": {
               "version": "2.0.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+              "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
               "dev": true
             },
             "ini": {
               "version": "1.3.5",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+              "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
               "dev": true,
               "optional": true
             },
             "is-fullwidth-code-point": {
               "version": "1.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+              "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
               "dev": true,
               "requires": {
                 "number-is-nan": "1.0.1"
@@ -14439,13 +12857,15 @@
             },
             "isarray": {
               "version": "1.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+              "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
               "dev": true,
               "optional": true
             },
             "minimatch": {
               "version": "3.0.4",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+              "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
               "dev": true,
               "requires": {
                 "brace-expansion": "1.1.11"
@@ -14453,12 +12873,14 @@
             },
             "minimist": {
               "version": "0.0.8",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+              "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
               "dev": true
             },
             "minipass": {
               "version": "2.3.5",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
+              "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
               "dev": true,
               "requires": {
                 "safe-buffer": "5.1.2",
@@ -14467,7 +12889,8 @@
             },
             "minizlib": {
               "version": "1.2.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
+              "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14476,7 +12899,8 @@
             },
             "mkdirp": {
               "version": "0.5.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+              "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
               "dev": true,
               "requires": {
                 "minimist": "0.0.8"
@@ -14484,13 +12908,15 @@
             },
             "ms": {
               "version": "2.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+              "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
               "dev": true,
               "optional": true
             },
             "needle": {
               "version": "2.2.4",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz",
+              "integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14501,7 +12927,8 @@
             },
             "node-pre-gyp": {
               "version": "0.10.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz",
+              "integrity": "sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14519,7 +12946,8 @@
             },
             "nopt": {
               "version": "4.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
+              "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14529,13 +12957,15 @@
             },
             "npm-bundled": {
               "version": "1.0.5",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz",
+              "integrity": "sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g==",
               "dev": true,
               "optional": true
             },
             "npm-packlist": {
               "version": "1.2.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.2.0.tgz",
+              "integrity": "sha512-7Mni4Z8Xkx0/oegoqlcao/JpPCPEMtUvsmB0q7mgvlMinykJLSRTYuFqoQLYgGY8biuxIeiHO+QNJKbCfljewQ==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14545,7 +12975,8 @@
             },
             "npmlog": {
               "version": "4.1.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+              "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14557,18 +12988,21 @@
             },
             "number-is-nan": {
               "version": "1.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+              "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
               "dev": true
             },
             "object-assign": {
               "version": "4.1.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+              "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
               "dev": true,
               "optional": true
             },
             "once": {
               "version": "1.4.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+              "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
               "dev": true,
               "requires": {
                 "wrappy": "1.0.2"
@@ -14576,19 +13010,22 @@
             },
             "os-homedir": {
               "version": "1.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+              "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
               "dev": true,
               "optional": true
             },
             "os-tmpdir": {
               "version": "1.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+              "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
               "dev": true,
               "optional": true
             },
             "osenv": {
               "version": "0.1.5",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
+              "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14598,19 +13035,22 @@
             },
             "path-is-absolute": {
               "version": "1.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+              "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
               "dev": true,
               "optional": true
             },
             "process-nextick-args": {
               "version": "2.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+              "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
               "dev": true,
               "optional": true
             },
             "rc": {
               "version": "1.2.8",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+              "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14622,7 +13062,8 @@
               "dependencies": {
                 "minimist": {
                   "version": "1.2.0",
-                  "bundled": true,
+                  "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+                  "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
                   "dev": true,
                   "optional": true
                 }
@@ -14630,7 +13071,8 @@
             },
             "readable-stream": {
               "version": "2.3.6",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+              "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14645,7 +13087,8 @@
             },
             "rimraf": {
               "version": "2.6.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+              "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14654,42 +13097,49 @@
             },
             "safe-buffer": {
               "version": "5.1.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+              "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
               "dev": true
             },
             "safer-buffer": {
               "version": "2.1.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+              "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
               "dev": true,
               "optional": true
             },
             "sax": {
               "version": "1.2.4",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+              "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
               "dev": true,
               "optional": true
             },
             "semver": {
               "version": "5.6.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
+              "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==",
               "dev": true,
               "optional": true
             },
             "set-blocking": {
               "version": "2.0.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+              "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
               "dev": true,
               "optional": true
             },
             "signal-exit": {
               "version": "3.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+              "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
               "dev": true,
               "optional": true
             },
             "string-width": {
               "version": "1.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+              "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
               "dev": true,
               "requires": {
                 "code-point-at": "1.1.0",
@@ -14699,7 +13149,8 @@
             },
             "string_decoder": {
               "version": "1.1.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+              "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14708,7 +13159,8 @@
             },
             "strip-ansi": {
               "version": "3.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+              "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
               "dev": true,
               "requires": {
                 "ansi-regex": "2.1.1"
@@ -14716,13 +13168,15 @@
             },
             "strip-json-comments": {
               "version": "2.0.1",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+              "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
               "dev": true,
               "optional": true
             },
             "tar": {
               "version": "4.4.8",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz",
+              "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14737,13 +13191,15 @@
             },
             "util-deprecate": {
               "version": "1.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+              "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
               "dev": true,
               "optional": true
             },
             "wide-align": {
               "version": "1.1.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+              "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
               "dev": true,
               "optional": true,
               "requires": {
@@ -14752,12 +13208,14 @@
             },
             "wrappy": {
               "version": "1.0.2",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+              "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
               "dev": true
             },
             "yallist": {
               "version": "3.0.3",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
+              "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
               "dev": true
             }
           }
@@ -15186,13 +13644,6 @@
         }
       }
     },
-    "window-size": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
-      "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
-      "dev": true,
-      "optional": true
-    },
     "wordwrap": {
       "version": "0.0.3",
       "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
@@ -15247,48 +13698,19 @@
       "dev": true
     },
     "ws": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.1.tgz",
-      "integrity": "sha1-CC3bbGQehdS7RR8D1S8G6r2x8Bg=",
+      "version": "6.2.1",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
+      "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
       "dev": true,
       "requires": {
-        "options": "0.0.6",
-        "ultron": "1.0.2"
+        "async-limiter": "1.0.0"
       }
     },
-    "wtf-8": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/wtf-8/-/wtf-8-1.0.0.tgz",
-      "integrity": "sha1-OS2LotDxw00e4tYw8V0O+2jhBIo=",
-      "dev": true
-    },
     "xhr2": {
       "version": "0.1.4",
       "resolved": "https://registry.npmjs.org/xhr2/-/xhr2-0.1.4.tgz",
       "integrity": "sha1-f4dliEdxbbUCYyOBL4GMras4el8="
     },
-    "xml2js": {
-      "version": "0.4.19",
-      "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz",
-      "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==",
-      "dev": true,
-      "requires": {
-        "sax": "1.2.4",
-        "xmlbuilder": "9.0.4"
-      }
-    },
-    "xmlbuilder": {
-      "version": "9.0.4",
-      "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.4.tgz",
-      "integrity": "sha1-UZy0ymhtAFqEINNJbz8MruzKWA8=",
-      "dev": true
-    },
-    "xmlhttprequest-ssl": {
-      "version": "1.5.3",
-      "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz",
-      "integrity": "sha1-GFqIjATspGw+QHDZn3tJ3jUomS0=",
-      "dev": true
-    },
     "xregexp": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz",
@@ -15379,12 +13801,6 @@
         }
       }
     },
-    "yeast": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz",
-      "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=",
-      "dev": true
-    },
     "yn": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/yn/-/yn-1.3.0.tgz",
diff --git a/services/self-service/src/main/resources/webapp/package.json b/services/self-service/src/main/resources/webapp/package.json
index ecb4388..4ab494b 100644
--- a/services/self-service/src/main/resources/webapp/package.json
+++ b/services/self-service/src/main/resources/webapp/package.json
@@ -9,19 +9,20 @@
     "test": "ng test",
     "lint": "ng lint",
     "e2e": "ng e2e",
-    "build.dev": "ng build --build-optimizer=false",
-    "build.prod": "ng build --prod"
+    "build.dev": "ng build --build-optimizer=false --stats-json",
+    "build.prod": "ng build --prod --stats-json",
+    "analyse": "webpack-bundle-analyzer dist/stats.json"
   },
   "private": true,
   "dependencies": {
-    "@angular/animations": "^8.0.0-beta.2",
-    "@angular/cdk": "^6.1",
+    "@angular/animations": "^7.2.15",
+    "@angular/cdk": "^7.3.7",
     "@angular/common": "^8.0.0-beta.2",
     "@angular/compiler": "^8.0.0-beta.2",
     "@angular/core": "^8.0.0-beta.2",
     "@angular/forms": "^8.0.0-beta.2",
     "@angular/http": "^8.0.0-beta.2",
-    "@angular/material": "^6.1",
+    "@angular/material": "^7.3.7",
     "@angular/material-moment-adapter": "^5.2.3",
     "@angular/platform-browser": "^8.0.0-beta.2",
     "@angular/platform-browser-dynamic": "^8.0.0-beta.2",
@@ -29,12 +30,9 @@
     "@angular/router": "^8.0.0-beta.2",
     "core-js": "2.4.1",
     "guacamole-common-js": "^1.0.0-b",
-    "hammerjs": "^2.0.8",
     "moment": "^2.20.1",
     "moment-timezone": "^0.5.16",
     "ng-daterangepicker": "^1.1.0",
-    "ng2-toastr": "^4.1.2",
-    "ngx-mat-daterange-picker": "^1.1.4",
     "ngx-toastr": "^9.1.2",
     "rxjs": "6.0.0",
     "rxjs-compat": "6.0.0",
@@ -46,22 +44,12 @@
     "@angular-devkit/build-angular": "^0.13.0",
     "@angular/cli": "^7.3.0",
     "@angular/compiler-cli": "^8.0.0-beta.2",
-    "@types/jasmine": "2.5.38",
     "@types/moment-timezone": "^0.5.4",
     "@types/node": "~6.0.60",
-    "codelyzer": "^3.0.1",
-    "jasmine-core": "~2.5.2",
-    "jasmine-spec-reporter": "~3.2.0",
-    "karma": "~1.4.1",
-    "karma-chrome-launcher": "~2.0.0",
-    "karma-cli": "~1.0.1",
-    "karma-coverage-istanbul-reporter": "^0.2.0",
-    "karma-jasmine": "~1.1.0",
-    "karma-jasmine-html-reporter": "^0.2.2",
     "node-sass": "^4.7.2",
-    "protractor": "~5.1.0",
     "ts-node": "~2.0.0",
     "tslint": "^5.15.0",
-    "typescript": "^3.2.4"
+    "typescript": "^3.2.4",
+    "webpack-bundle-analyzer": "^3.3.2"
   }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/access-denied/access-denied.component.scss b/services/self-service/src/main/resources/webapp/src/app/access-denied/access-denied.component.scss
index df52859..eb3eac2 100644
--- a/services/self-service/src/main/resources/webapp/src/app/access-denied/access-denied.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/access-denied/access-denied.component.scss
@@ -17,14 +17,9 @@
  * under the License.
  */
 .no-access-page {
-  position: absolute;
-  top: 0;
-  left: 0;
-  width: 100%;
   height: 100%;
   background: #f5f5f5;
   color: #8c8888;
-  z-index: -1;
   .content {
     position: absolute;
     top: 0;
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/billing/cost-details-dialog/index.ts b/services/self-service/src/main/resources/webapp/src/app/administration/administration.module.ts
similarity index 67%
copy from services/self-service/src/main/resources/webapp/src/app/resources/billing/cost-details-dialog/index.ts
copy to services/self-service/src/main/resources/webapp/src/app/administration/administration.module.ts
index 859295e..e535bda 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/billing/cost-details-dialog/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/administration.module.ts
@@ -20,15 +20,13 @@
 import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
 
-import { MaterialModule } from '../../../shared/material.module';
-import { CostDetailsDialogComponent } from './cost-details-dialog.component';
-import { ModalModule } from '../../../shared';
-
-export * from './cost-details-dialog.component';
+import { ManagenementModule } from './management';
+import { ProjectModule } from './project';
+import { RolesModule } from './roles';
 
 @NgModule({
-  imports: [CommonModule, ModalModule, MaterialModule],
-  declarations: [CostDetailsDialogComponent],
-  exports: [CostDetailsDialogComponent]
+  imports: [CommonModule, ManagenementModule, ProjectModule, RolesModule],
+  declarations: [],
+  exports: [ManagenementModule, ProjectModule, RolesModule]
 })
-export class CostDetailsDialogModule {}
+export class AdministrationModule { }
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/backup-dilog/backup-dilog.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/management/backup-dilog/backup-dilog.component.html
similarity index 89%
rename from services/self-service/src/main/resources/webapp/src/app/management/backup-dilog/backup-dilog.component.html
rename to services/self-service/src/main/resources/webapp/src/app/administration/management/backup-dilog/backup-dilog.component.html
index 9c797ad..545c236 100644
--- a/services/self-service/src/main/resources/webapp/src/app/management/backup-dilog/backup-dilog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/backup-dilog/backup-dilog.component.html
@@ -17,12 +17,13 @@
   ~ under the License.
   -->
 
-<modal-dialog #bindDialog modalClass="backup-dialog modal-sm">
-  <modal-header>
+<div class="backup-dialog" id="dialog-box">
+  <header class="dialog-header">
     <h4 class="modal-title">Backup options</h4>
-  </modal-header>
-  <modal-content>
-    <div class="content-box" *ngIf="backupOptions">
+    <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+  </header>
+  <div class="dialog-content">
+    <div id="backup-options" class="content-box" *ngIf="backupOptions">
       <div class="hold-block">
         <mat-slide-toggle
           labelPosition="before"
@@ -72,11 +73,11 @@
         </mat-slide-toggle>
       </div>
       <div class="text-center m-top-30 m-bott-10">
-        <button mat-raised-button type="button" class="butt" (click)="bindDialog.close(); backupOptions.setDegault()">
+        <button mat-raised-button type="button" class="butt" (click)="dialogRef.close(); backupOptions.setDegault()">
           Cancel
         </button>
         <button mat-raised-button type="button" (click)="applyOptions()" class="butt butt-success" [disabled]="!valid">Apply</button>
       </div>
     </div>
-  </modal-content>
-</modal-dialog>
+  </div>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/backup-dilog/backup-dilog.component.scss b/services/self-service/src/main/resources/webapp/src/app/administration/management/backup-dilog/backup-dilog.component.scss
similarity index 100%
rename from services/self-service/src/main/resources/webapp/src/app/management/backup-dilog/backup-dilog.component.scss
rename to services/self-service/src/main/resources/webapp/src/app/administration/management/backup-dilog/backup-dilog.component.scss
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/backup-dilog/backup-dilog.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/backup-dilog/backup-dilog.component.ts
new file mode 100644
index 0000000..feaf25f
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/backup-dilog/backup-dilog.component.ts
@@ -0,0 +1,105 @@
+/*
+ * 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, Output, EventEmitter, Inject } from '@angular/core';
+import { DICTIONARY } from '../../../../dictionary/global.dictionary';
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
+import { ToastrService } from 'ngx-toastr';
+
+import { BackupOptionsModel } from '../management.model';
+import { BackupService } from '../../../core/services';
+
+@Component({
+  selector: 'dlab-backup-dilog',
+  templateUrl: './backup-dilog.component.html',
+  styleUrls: ['./backup-dilog.component.scss']
+})
+export class BackupDilogComponent implements OnInit {
+  readonly DICTIONARY = DICTIONARY;
+  public backupOptions: BackupOptionsModel = new BackupOptionsModel([], [], [], [], false, false);
+  public valid: boolean = true;
+
+  private clear = undefined;
+  @Output() preventbackup: EventEmitter<{}> = new EventEmitter();
+
+  constructor(
+    @Inject(MAT_DIALOG_DATA) public data: any,
+    public dialogRef: MatDialogRef<BackupDilogComponent>,
+    public toastr: ToastrService,
+    private backupService: BackupService,
+  ) { }
+
+  ngOnInit() {
+    this.backupOptions.setDegault();
+    this.valid = true;
+  }
+
+  public onHoldChanged($event, key): void {
+    this.backupOptions[key] instanceof Array
+      ? (this.backupOptions[key][0] = $event.checked ? 'all' : 'skip')
+      : (this.backupOptions[key] = !this.backupOptions[key]);
+
+    this.checkValidity();
+  }
+
+  public applyOptions(): void {
+    this.backupService.createBackup(this.backupOptions).subscribe(result => {
+      this.getBackupStatus(result);
+      this.toastr.success('Backup configuration is processing!', 'Processing!');
+      this.clear = window.setInterval(() => this.getBackupStatus(result), 3000);
+      this.dialogRef.close(this.backupOptions);
+    },
+      error => this.toastr.error(error.message, 'Oops!'));
+  }
+
+  private checkValidity(): void {
+    const items = [];
+
+    Object.keys(this.backupOptions).forEach(el => {
+      if (this.backupOptions[el] instanceof Array) {
+        if (this.backupOptions[el][0] && this.backupOptions[el][0] !== 'skip') items.push(this.backupOptions[el][0]);
+      } else {
+        if (this.backupOptions[el]) items.push(this.backupOptions[el]) ;
+      }
+    });
+
+    this.valid = items.length > 0;
+  }
+
+  private getBackupStatus(result) {
+    debugger;
+    const uuid = result.body;
+    this.backupService.getBackupStatus(uuid)
+      .subscribe((backupStatus: any) => {
+        if (!this.creatingBackup) {
+          backupStatus.status === 'FAILED'
+            ? this.toastr.error('Backup configuration failed!', 'Oops!')
+            : this.toastr.success('Backup configuration completed!', 'Success!');
+          clearInterval(this.clear);
+        }
+      }, () => {
+        clearInterval(this.clear);
+        this.toastr.error('Backup configuration failed!', 'Oops!');
+      });
+  }
+
+  get creatingBackup(): boolean {
+    return this.backupService.inProgress;
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/endpoints/endpoints.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/management/endpoints/endpoints.component.html
new file mode 100644
index 0000000..d054f97
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/endpoints/endpoints.component.html
@@ -0,0 +1,137 @@
+<!--
+  ~ 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="endpoints-dialog" id="dialog-box">
+  <header class="dialog-header">
+    <h4 class="modal-title">Create endpoint</h4>
+    <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+  </header>
+  <div class="dialog-content tabs">
+    <div class="content-box">
+      <mat-tab-group #tabGroup>
+        <mat-tab label="CREATE ENDPOINT">
+          <div class="split">
+            <form [formGroup]="createEndpointForm" novalidate>
+              <div class="control-group">
+                <label class="label">Name</label>
+                <div class="control">
+                  <input type="text" formControlName="name" placeholder="Enter endpoint name">
+                  <span class="error"
+                    *ngIf="!createEndpointForm?.controls.name.valid && createEndpointForm?.controls.name.touched">
+                    Endpoint name can only contain letters, numbers, hyphens and '_' but can not end with special
+                    characters
+                  </span>
+                </div>
+              </div>
+              <div class="control-group">
+                <label class="label">Endpoint url</label>
+                <div class="control">
+                  <input type="text" formControlName="url" placeholder="Enter endpoint url">
+                  <span class="error"
+                    *ngIf="!createEndpointForm?.controls.url.valid && createEndpointForm.controls.url.touched">
+                    Endpoint url can only contain letters, numbers, hyphens and '_' but can not end with special
+                    characters
+                  </span>
+                </div>
+              </div>
+              <div class="control-group">
+                <label class="label">Account</label>
+                <div class="control">
+                  <input type="text" formControlName="account" placeholder="Enter account">
+                  <span class="error"
+                    *ngIf="!createEndpointForm?.controls.account.valid && createEndpointForm.controls.account.touched">
+                    Endpoint account can only contain letters, numbers, hyphens and '_' but can not end with special
+                    characters
+                  </span>
+                </div>
+              </div>
+              <div class="control-group">
+                <label class="label">Endpoint tag</label>
+                <div class="control">
+                  <input type="text" formControlName="endpoint_tag" placeholder="Enter endpoint tag">
+                  <span class="error"
+                    *ngIf="!createEndpointForm?.controls.endpoint_tag.valid && createEndpointForm.controls.endpoint_tag.touched">
+                    Endpoint tag can only contain letters, numbers, hyphens and '_' but can not end with special
+                    characters
+                  </span>
+                </div>
+              </div>
+            </form>
+            <div class="action-group m-bott-10">
+              <button mat-raised-button type="button" class="butt action" (click)="dialogRef.close()">Cancel</button>
+              <button mat-raised-button type="button" [disabled]="!createEndpointForm.valid"
+                (click)="assignChanges(createEndpointForm.value)" class="butt butt-success action">Create</button>
+            </div>
+          </div>
+        </mat-tab>
+        <mat-tab label="ENDPOINTS LIST">
+          <div class="endpoints">
+            <table mat-table [dataSource]="endpoints" class="endpoints-table"
+              *ngIf="endpoints?.length; else empty">
+              <ng-container matColumnDef="name">
+                <th mat-header-cell *matHeaderCellDef class="name"> Endpoint name </th>
+                <td mat-cell *matCellDef="let element"> {{element.name}} </td>
+              </ng-container>
+
+              <ng-container matColumnDef="url">
+                <th mat-header-cell *matHeaderCellDef class="url"> Url </th>
+                <td mat-cell *matCellDef="let element"> {{element.url}} </td>
+              </ng-container>
+
+              <ng-container matColumnDef="account">
+                <th mat-header-cell *matHeaderCellDef class="account"> Account </th>
+                <td mat-cell *matCellDef="let element"> {{element.account}} </td>
+              </ng-container>
+
+              <ng-container matColumnDef="endpoint_tag">
+                <th mat-header-cell *matHeaderCellDef class="account"> Endpoint tag </th>
+                <td mat-cell *matCellDef="let element"> {{element.endpoint_tag}} </td>
+              </ng-container>
+
+              <ng-container matColumnDef="actions">
+                <th mat-header-cell *matHeaderCellDef class="actions"></th>
+                <td mat-cell *matCellDef="let element" class="actions">
+                  <span (click)="deleteEndpoint(element)">
+                    <mat-icon>delete_forever</mat-icon>
+                  </span>
+                </td>
+              </ng-container>
+
+              <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
+              <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
+            </table>
+
+            <ng-template #empty>
+              <div class="info empty-box">
+                <div class="content">
+                  <p>Looks like you don't have any endpoints</p>
+
+                  <button mat-raised-button class="butt" (click)="tabGroup.selectedIndex = 0" [disabled]="creatingBackup">
+                    <i class="material-icons">settings_system_daydream</i>New endpoint
+                  </button>
+                </div>
+              </div>
+            </ng-template>
+          </div>
+        </mat-tab>
+      </mat-tab-group>
+    </div>
+  </div>
+</div>
\ No newline at end of file
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/endpoints/endpoints.component.scss b/services/self-service/src/main/resources/webapp/src/app/administration/management/endpoints/endpoints.component.scss
new file mode 100644
index 0000000..f6851ee
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/endpoints/endpoints.component.scss
@@ -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.
+ */
+
+.content-box {
+  padding: 10px 30px 30px;
+  height: 400px;
+  .split {
+    display: flex;
+    flex-direction: column;
+    justify-content: space-between;
+    height: 100%;
+    form {
+      padding: 20px 10px;
+      .control-group {
+        .error {
+          position: absolute;
+          right: 0;
+          bottom: 5px;
+          font-family: 'Open Sans', sans-serif;
+          font-weight: 300;
+        }
+      }
+    }
+  }
+  .action-group {
+    text-align: center;
+  }
+  .endpoints {
+    height: 265px;
+    table {
+      width: 100%;
+      .actions {
+        color: #607d8b;
+        width: 10%;
+        text-align: center;
+        span {
+          transition: all .5s ease-in-out;
+          cursor: pointer;
+          .mat-icon {
+            font-size: 18px;
+            padding-top: 5px;
+          }
+          &:hover {
+            color: darken(#607d8b, 10%);
+          }
+        }
+      }
+    }
+    .content {
+      p {
+        margin-bottom: 30px;
+      }
+    }
+  }
+}
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
new file mode 100644
index 0000000..3f8a1d9
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/endpoints/endpoints.component.ts
@@ -0,0 +1,88 @@
+/*
+ * 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, Inject } from '@angular/core';
+import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+import { MatDialogRef, MAT_DIALOG_DATA, MatDialog } from '@angular/material';
+import { ToastrService } from 'ngx-toastr';
+
+import { EndpointService } from '../../../core/services';
+import { NotificationDialogComponent } from '../../../shared/modal-dialog/notification-dialog';
+import { PATTERNS } from '../../../core/util';
+
+export interface Endpoint {
+  name: string;
+  url: string;
+  account: string;
+}
+
+@Component({
+  selector: 'endpoints',
+  templateUrl: './endpoints.component.html',
+  styleUrls: ['./endpoints.component.scss']
+})
+export class EndpointsComponent implements OnInit {
+  public createEndpointForm: FormGroup;
+  endpoints: Endpoint[] = [];
+  displayedColumns: string[] = ['name', 'url', 'account', 'endpoint_tag', 'actions'];
+
+  constructor(
+    @Inject(MAT_DIALOG_DATA) public data: any,
+    public toastr: ToastrService,
+    public dialogRef: MatDialogRef<EndpointsComponent>,
+    public dialog: MatDialog,
+    private endpointService: EndpointService,
+    private _fb: FormBuilder
+  ) { }
+
+  ngOnInit() {
+    this.initFormModel();
+    this.getEndpointList();
+  }
+
+  public assignChanges(data) {
+    this.endpointService.createEndpoint(data).subscribe(() => {
+      this.toastr.success('Endpoint created successfully!', 'Success!');
+      this.dialogRef.close(true);
+    }, error => this.toastr.error(error.message || 'Endpoint creation failed!', 'Oops!'));
+  }
+
+  public deleteEndpoint(data) {
+    this.dialog.open(NotificationDialogComponent, { data: { type: 'confirmation', item: data }, panelClass: 'modal-sm' })
+      .afterClosed().subscribe(result => {
+        result && this.endpointService.deleteEndpoint(data.name).subscribe(() => {
+          this.toastr.success('Endpoint successfully deleted!', 'Success!');
+          this.getEndpointList();
+        }, error => this.toastr.error(error.message || 'Endpoint creation failed!', 'Oops!'));
+      });
+  }
+
+  private initFormModel(): void {
+    this.createEndpointForm = this._fb.group({
+      name: ['', Validators.compose([Validators.required, Validators.pattern(PATTERNS.namePattern)])],
+      url: ['', Validators.compose([Validators.required, Validators.pattern(PATTERNS.url)])],
+      account: ['', Validators.compose([Validators.required, Validators.pattern(PATTERNS.namePattern)])],
+      endpoint_tag: ['', Validators.compose([Validators.required, Validators.pattern(PATTERNS.namePattern)])]
+    });
+  }
+
+  private getEndpointList() {
+    this.endpointService.getEndpointsData().subscribe((endpoints: any) => this.endpoints = endpoints);
+  }
+}
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
new file mode 100644
index 0000000..8d03ac0
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/index.ts
@@ -0,0 +1,75 @@
+/*
+ * 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 { FormsModule, ReactiveFormsModule } from '@angular/forms';
+
+import { BubbleModule, ConfirmationDialogModule } from '../../shared';
+import { MaterialModule } from '../../shared/material.module';
+
+import { ManagementComponent } from './management.component';
+import { ManagementGridComponent, ReconfirmationDialogComponent } from './management-grid/management-grid.component';
+import { ComputationalResourcesModule } from '../../resources/computational/computational-resources-list';
+
+import { FormControlsModule } from '../../shared/form-controls';
+import { BackupDilogComponent } from './backup-dilog/backup-dilog.component';
+import { ManageEnvironmentComponent, ConfirmActionDialogComponent } from './manage-environment/manage-environment-dilog.component';
+
+import { DirectivesModule } from '../../core/directives';
+
+import { SsnMonitorComponent } from './ssn-monitor/ssn-monitor.component';
+import { EndpointsComponent } from './endpoints/endpoints.component';
+import { ProjectModule } from '../project';
+
+export * from './management.component';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    ReactiveFormsModule,
+    ProjectModule,
+    BubbleModule,
+    ConfirmationDialogModule,
+    ComputationalResourcesModule,
+    FormControlsModule,
+    DirectivesModule,
+    MaterialModule
+  ],
+  declarations: [
+    ManagementComponent,
+    ManagementGridComponent,
+    BackupDilogComponent,
+    ManageEnvironmentComponent,
+    ReconfirmationDialogComponent,
+    ConfirmActionDialogComponent,
+    SsnMonitorComponent,
+    EndpointsComponent
+  ],
+  entryComponents: [
+    ReconfirmationDialogComponent,
+    ConfirmActionDialogComponent,
+    BackupDilogComponent,
+    SsnMonitorComponent,
+    EndpointsComponent,
+    ManageEnvironmentComponent],
+  exports: [ManagementComponent]
+})
+export class ManagenementModule { }
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/manage-environment/manage-environment-dilog.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/management/manage-environment/manage-environment-dilog.component.html
similarity index 89%
rename from services/self-service/src/main/resources/webapp/src/app/management/manage-environment/manage-environment-dilog.component.html
rename to services/self-service/src/main/resources/webapp/src/app/administration/management/manage-environment/manage-environment-dilog.component.html
index 094ec9b..3f183bd 100644
--- a/services/self-service/src/main/resources/webapp/src/app/management/manage-environment/manage-environment-dilog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/manage-environment/manage-environment-dilog.component.html
@@ -17,13 +17,14 @@
   ~ under the License.
   -->
 
-<modal-dialog #bindDialog modalClass="manage-env-dialog modal-xl-s">
-  <modal-header>
+<div id="dialog-box" class="manage-env-dialog">
+  <header class="dialog-header">
     <h4 class="modal-title">Manage environment</h4>
-  </modal-header>
-  <modal-content>
+    <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+  </header>
+  <div class="dialog-content">
     <div class="content-box">
-      <div *ngIf="usersList.length">
+      <div *ngIf="data.usersList?.length">
         <form [formGroup]="manageUsersForm" (submit)="setBudgetLimits(manageUsersForm.value)" novalidate>
           <mat-list>
             <mat-list-item class="list-header">
@@ -60,14 +61,14 @@
               </div>
             </div>
             <div class="text-center m-top-30" *ngIf="DICTIONARY.cloud_provider !== 'gcp'">
-              <button mat-raised-button type="button" (click)="bindDialog.close()" class="butt action">Cancel</button>
+              <button mat-raised-button type="button" (click)="dialogRef.close()" class="butt action">Cancel</button>
               <button mat-raised-button type="submit" [disabled]="!manageUsersForm.valid"
                       class="butt butt-success" [ngClass]="{'not-allowed': !manageUsersForm.valid}">Apply</button>
             </div>
           </mat-list>
         </form>
       </div>
-      <div class="info message" *ngIf="!usersList.length">No active users environments</div>
+      <div class="info message" *ngIf="!data?.usersList.length">No active users environments</div>
     </div>
-  </modal-content>
-</modal-dialog>
+  </div>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/manage-environment/manage-environment-dilog.component.scss b/services/self-service/src/main/resources/webapp/src/app/administration/management/manage-environment/manage-environment-dilog.component.scss
similarity index 100%
rename from services/self-service/src/main/resources/webapp/src/app/management/manage-environment/manage-environment-dilog.component.scss
rename to services/self-service/src/main/resources/webapp/src/app/administration/management/manage-environment/manage-environment-dilog.component.scss
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/manage-environment/manage-environment-dilog.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/manage-environment/manage-environment-dilog.component.ts
similarity index 85%
rename from services/self-service/src/main/resources/webapp/src/app/management/manage-environment/manage-environment-dilog.component.ts
rename to services/self-service/src/main/resources/webapp/src/app/administration/management/manage-environment/manage-environment-dilog.component.ts
index 6a6d025..8831fd9 100644
--- a/services/self-service/src/main/resources/webapp/src/app/management/manage-environment/manage-environment-dilog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/manage-environment/manage-environment-dilog.component.ts
@@ -17,10 +17,10 @@
  * under the License.
  */
 
-import { Component, ViewChild, Output, EventEmitter, ViewEncapsulation, Inject } from '@angular/core';
+import { Component, Output, EventEmitter, ViewEncapsulation, Inject, OnInit } from '@angular/core';
 import { Validators, FormBuilder, FormGroup, FormArray } from '@angular/forms';
 import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
-import { DICTIONARY } from '../../../dictionary/global.dictionary';
+import { DICTIONARY } from '../../../../dictionary/global.dictionary';
 
 @Component({
   selector: 'dlab-manage-env-dilog',
@@ -28,40 +28,38 @@
   styleUrls: ['./manage-environment-dilog.component.scss'],
   encapsulation: ViewEncapsulation.None
 })
-export class ManageEnvironmentComponent {
+export class ManageEnvironmentComponent implements OnInit {
   readonly DICTIONARY = DICTIONARY;
-  public usersList: Array<string> = [];
+  // public usersList: Array<string> = [];
   public manageUsersForm: FormGroup;
   public manageTotalsForm: FormGroup;
 
-  @ViewChild('bindDialog') bindDialog;
   @Output() manageEnv: EventEmitter<{}> = new EventEmitter();
-  @Output() setBudget: EventEmitter<{}> = new EventEmitter();
+  // @Output() setBudget: EventEmitter<{}> = new EventEmitter();
 
   constructor(
+    @Inject(MAT_DIALOG_DATA) public data: any,
     private _fb: FormBuilder,
-    public dialog: MatDialog
+    public dialog: MatDialog,
+    public dialogRef: MatDialogRef<ManageEnvironmentComponent>
   ) { }
 
+  ngOnInit() {
+    !this.manageUsersForm && this.initForm();
+
+    this.manageUsersForm.setControl('users',
+    this._fb.array((this.data.usersList || []).map((x: any) => this._fb.group({
+      name: x.name, budget: [x.budget, [Validators.min(0), this.userValidityCheck.bind(this)]], status: x.status
+    }))));
+    this.manageUsersForm.controls['total'].setValue(this.data.total.conf_max_budget || null);
+  }
+
   get usersEnvironments(): FormArray {
     return <FormArray>this.manageUsersForm.get('users');
   }
 
-  public open(param, data, settings): void {
-    this.usersList = data;
-    !this.manageUsersForm && this.initForm();
-
-    this.manageUsersForm.setControl('users',
-    this._fb.array((this.usersList || []).map((x: any) => this._fb.group({
-      name: x.name, budget: [x.budget, [Validators.min(0), this.userValidityCheck.bind(this)]], status: x.status
-    }))));
-    this.manageUsersForm.controls['total'].setValue(settings.conf_max_budget || null);
-    this.bindDialog.open(param);
-  }
-
   public setBudgetLimits(value) {
-    this.setBudget.emit(value);
-    this.bindDialog.close();
+    this.dialogRef.close(value);
   }
 
   public applyAction(action, user) {
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
new file mode 100644
index 0000000..ce66673
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
@@ -0,0 +1,127 @@
+<!--
+  ~ 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="ani">
+  <table mat-table [dataSource]="allEnvironmentData" class="data-grid mat-elevation-z6">
+    <ng-container matColumnDef="user">
+      <th mat-header-cell *matHeaderCellDef class="user"> User </th>
+      <td mat-cell *matCellDef="let element">{{ element.user }}</td>
+    </ng-container>
+
+    <ng-container matColumnDef="type">
+      <th mat-header-cell *matHeaderCellDef class="type"> Type </th>
+      <td mat-cell *matCellDef="let element">{{ element.name }}</td>
+    </ng-container>
+
+    <ng-container matColumnDef="shape">
+      <th mat-header-cell *matHeaderCellDef class="shape"> Shape / Resource id </th>
+      <td mat-cell *matCellDef="let element" class="shape">{{ element.shape || element.ip }}</td>
+    </ng-container>
+
+    <ng-container matColumnDef="status">
+      <th mat-header-cell *matHeaderCellDef class="status"> Status </th>
+      <td mat-cell *matCellDef="let element" class="ani status" ngClass="{{element.status || ''}}">{{ element.status }}
+      </td>
+    </ng-container>
+
+    <ng-container matColumnDef="resources">
+      <th mat-header-cell *matHeaderCellDef class="resources"> Computational resources </th>
+      <td mat-cell *matCellDef="let element" class="ani resources">
+        <div class="source" *ngIf="element.resources">
+          <div *ngIf="!element.resources?.length">
+            <span *ngIf="!element.resources.length" class="no-details">no details</span>
+          </div>
+          <div *ngIf="element.resources?.length">
+            <div *ngFor="let resource of element.resources" class="resource-wrap">
+              <div class="resource-name">
+                <a class="detailed-link">
+                  {{ resource.computational_name }}
+                </a>
+              </div>
+              <span ngClass="{{resource.status || ''}}" class="resource-status">{{ resource.status }}</span>
+              <div class="resource-actions">
+                <a class="start-stop-action" *ngIf="resource.image === 'docker.dlab-dataengine'">
+                  <i class="material-icons" (click)="toggleResourceAction(element, 'stop', resource)"
+                    [ngClass]="{'not-allowed' : resource.status !== 'running' }">pause_circle_outline</i>
+                </a>
+
+                <a class="remove_butt" (click)="toggleResourceAction(element, 'terminate', resource)"
+                  [ngClass]="{ 'disabled' : element.status !== 'running' || resource.status !== 'running' && resource.status !== 'stopped' }">
+                  <i class="material-icons">highlight_off</i>
+                </a>
+              </div>
+            </div>
+          </div>
+        </div>
+      </td>
+    </ng-container>
+
+    <ng-container matColumnDef="actions">
+      <th mat-header-cell *matHeaderCellDef class="actions"></th>
+      <td mat-cell *matCellDef="let element" class="actions settings">
+        <span #settings class="actions" (click)="actions.toggle($event, settings)"
+          [ngClass]="{ 'disabled'
+            : (element.status !== 'running' && element.status !== 'stopped' && element.status !== 'stopping' && element.status !== 'failed' )
+            || (element.type === 'edge node' && element.user.toLowerCase() === currentUser && element.status === 'stopping')
+            || element.type === 'edge node' && element.user.toLowerCase() !== currentUser && element.status !== 'running' }"></span>
+        <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' : 'Unable to stop edge node because at least one resource of this user is in progress' }}"
+              matTooltipPosition="above" [matTooltipDisabled]="!isResourcesInProgress(element)"
+              [hidden]="element.name === 'edge node' && element.status === 'stopped'">
+              <div (click)="toggleResourceAction(element, 'stop')"
+                [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 *ngIf="element.name !== 'edge node'"
+              matTooltip="Unable to terminate notebook because at least one computational resource is in progress"
+              matTooltipPosition="above" [matTooltipDisabled]="!isResourcesInProgress(element)">
+              <div (click)="toggleResourceAction(element, 'terminate')"
+                [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.user.toLowerCase() === currentUser">
+              <li (click)="toggleResourceAction(element, 'run')" *ngIf="element.status === 'stopped'">
+                <i class="material-icons">play_circle_outline</i>
+                <span>Start</span>
+              </li>
+            </div>
+          </ul>
+        </bubble-up>
+      </td>
+    </ng-container>
+    <ng-container matColumnDef="placeholder">
+      <td mat-footer-cell *matFooterCellDef colspan="6" class="info">
+        To start working, please, create new environment
+      </td>
+    </ng-container>
+
+    <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+    <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
+
+    <tr [hidden]="allEnvironmentData?.length" mat-footer-row *matFooterRowDef="['placeholder']"></tr>
+  </table>
+
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.scss b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.scss
similarity index 94%
rename from services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.scss
rename to services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.scss
index 6198578..e2f7646 100644
--- a/services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.scss
@@ -38,3 +38,10 @@
 .source .resource-wrap .resource-name .detailed-link {
   cursor: default !important;
 }
+
+table {
+  width: 100%;
+  .actions {
+    text-align: right;
+  }
+}
\ No newline at end of file
diff --git a/services/self-service/src/main/resources/webapp/src/app/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
similarity index 63%
rename from services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.ts
rename to services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
index b5297b2..c6014db 100644
--- a/services/self-service/src/main/resources/webapp/src/app/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
@@ -21,9 +21,9 @@
 import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
 import { ToastrService } from 'ngx-toastr';
 
-import { HealthStatusService, UserAccessKeyService } from '../../core/services';
-import { ConfirmationDialogType } from '../../shared';
-import { FileUtils } from '../../core/util';
+import { HealthStatusService } from '../../../core/services';
+import { ConfirmationDialogType } from '../../../shared';
+import { ConfirmationDialogComponent } from '../../../shared/modal-dialog/confirmation-dialog';
 
 export interface ManageAction {
   action: string;
@@ -36,30 +36,26 @@
   templateUrl: 'management-grid.component.html',
   styleUrls: [
     './management-grid.component.scss',
-    '../../resources/resources-grid/resources-grid.component.css',
-    '../../resources/computational/computational-resources-list/computational-resources-list.component.scss'
+    '../../../resources/resources-grid/resources-grid.component.css',
+    '../../../resources/computational/computational-resources-list/computational-resources-list.component.scss'
   ]
 })
 export class ManagementGridComponent implements OnInit {
   @Input() allEnvironmentData: Array<any>;
   @Input() environmentsHealthStatuses: Array<any>;
-  @Input() healthStatus: string;
   @Input() resources: Array<any>;
-  @Input() uploadKey: boolean;
   @Input() isAdmin: boolean;
   @Input() currentUser: string = '';
   @Output() refreshGrid: EventEmitter<{}> = new EventEmitter();
   @Output() actionToggle: EventEmitter<ManageAction> = new EventEmitter();
 
-  @ViewChild('confirmationDialog') confirmationDialog;
-  @ViewChild('keyReuploadDialog') keyReuploadDialog;
+  displayedColumns: string[] = ['user', 'type', 'shape', 'status', 'resources', 'actions'];
 
   constructor(
     private healthStatusService: HealthStatusService,
-    private userAccessKeyService: UserAccessKeyService,
     public toastr: ToastrService,
     public dialog: MatDialog
-  ) {}
+  ) { }
 
   ngOnInit() {
   }
@@ -71,40 +67,35 @@
   toggleResourceAction(environment, action: string, resource?) {
     if (resource) {
       const resource_name = resource ? resource.computational_name : environment.name;
-      const dialogRef: MatDialogRef<ConfirmationDialogComponent> = this.dialog.open(ConfirmationDialogComponent, {
+      this.dialog.open(ReconfirmationDialogComponent, {
         data: { action, resource_name, user: environment.user },
-        width: '550px',
-        panelClass: 'error-modalbox'
-      });
-      dialogRef.afterClosed().subscribe(result => {
+        width: '550px', panelClass: 'error-modalbox'
+      }).afterClosed().subscribe(result => {
         result && this.actionToggle.emit({ action, environment, resource });
       });
     } else {
+      const type = (environment.name === 'edge node' || environment.type.toLowerCase() === 'edge node')
+        ? ConfirmationDialogType.StopEdgeNode : ConfirmationDialogType.StopExploratory;
+
       if (action === 'stop') {
-        this.confirmationDialog.open(
-          { isFooter: false },
-          environment,
-          (environment.name === 'edge node' || environment.type.toLowerCase() === 'edge node')
-            ? ConfirmationDialogType.StopEdgeNode
-            : ConfirmationDialogType.StopExploratory,
-          );
+        this.dialog.open(ConfirmationDialogComponent, {
+          data: { notebook: environment, type: type, manageAction: this.isAdmin }, panelClass: 'modal-md'
+        }).afterClosed().subscribe(() => this.buildGrid());
       } else if (action === 'terminate') {
-        this.confirmationDialog.open({ isFooter: false }, environment, ConfirmationDialogType.TerminateExploratory);
+        this.dialog.open(ConfirmationDialogComponent, {
+          data: { notebook: environment, type: ConfirmationDialogType.TerminateExploratory, manageAction: this.isAdmin }, panelClass: 'modal-md'
+        }).afterClosed().subscribe(() => this.buildGrid());
       } else if (action === 'run') {
-        this.healthStatusService
-          .runEdgeNode()
-          .subscribe(() => {
-            this.buildGrid();
-            this.toastr.success('Edge node is starting!', 'Processing!');
-          }, error => 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!');
-            }, error => this.toastr.error('Edge Node recreation failed!', 'Oops!'));
-        }
+        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!'));
+      }
     }
   }
 
@@ -128,17 +119,6 @@
       && resource.status !== 'running'
       && resource.status !== 'stopped')).length > 0;
   }
-
-  showReuploaKeydDialog() {
-    this.keyReuploadDialog.open({ isFooter: false });
-  }
-
-  public generateUserKey() {
-    this.userAccessKeyService.regenerateAccessKey().subscribe(data => {
-      FileUtils.downloadFile(data);
-      this.buildGrid();
-    });
-  }
 }
 
 
@@ -164,9 +144,9 @@
   styles: [
   ]
 })
-export class ConfirmationDialogComponent {
+export class ReconfirmationDialogComponent {
   constructor(
-    public dialogRef: MatDialogRef<ConfirmationDialogComponent>,
+    public dialogRef: MatDialogRef<ReconfirmationDialogComponent>,
     @Inject(MAT_DIALOG_DATA) public data: any
-  ) {}
+  ) { }
 }
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
new file mode 100644
index 0000000..16e9f5d
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.html
@@ -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.
+  -->
+
+<div class="base-retreat">
+  <div class="sub-nav">
+    <div *ngIf="healthStatus?.admin" class="admin-group">
+      <button mat-raised-button class="butt ssn" (click)="showEndpointsDialog()">
+        <i class="material-icons"></i>Endpoints
+      </button>
+      <button mat-raised-button class="butt ssn" (click)="openSsnMonitorDialog()">
+        <i class="material-icons"></i>SSN Monitor
+      </button>
+      <button mat-raised-button class="butt env" (click)="openManageEnvironmentDialog()">
+        <i class="material-icons"></i>Manage environment
+      </button>
+      <button mat-raised-button class="butt" (click)="showBackupDialog()" [disabled]="creatingBackup">
+        <i class="material-icons">backup</i>Backup
+      </button>
+    </div>
+    <button mat-raised-button class="butt" (click)="buildGrid()">
+      <i class="material-icons">autorenew</i>Refresh
+    </button>
+  </div>
+  <mat-divider></mat-divider>
+  <management-grid
+    [currentUser]="user.toLowerCase()" [isAdmin]="healthStatus?.admin"
+    [allEnvironmentData]="allEnvironmentData" [environmentsHealthStatuses]="healthStatus?.list_resources"
+    (refreshGrid)="buildGrid()" (actionToggle)="manageEnvironmentAction($event)">
+  </management-grid>
+</div>
\ No newline at end of file
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/management.component.scss b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.scss
similarity index 100%
rename from services/self-service/src/main/resources/webapp/src/app/management/management.component.scss
rename to services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.scss
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
new file mode 100644
index 0000000..0db2a3c
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
@@ -0,0 +1,188 @@
+/*
+ * 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 { MatDialog } from '@angular/material';
+import { ToastrService } from 'ngx-toastr';
+
+import {
+  HealthStatusService,
+  ManageEnvironmentsService,
+  BackupService,
+  UserResourceService,
+  StorageService
+} from '../../core/services';
+
+import { EnvironmentModel, GeneralEnvironmentStatus } 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';
+import { ManageEnvironmentComponent } from './manage-environment/manage-environment-dilog.component';
+import { EndpointsComponent } from './endpoints/endpoints.component';
+
+@Component({
+  selector: 'environments-management',
+  templateUrl: './management.component.html',
+  styleUrls: ['./management.component.scss']
+})
+export class ManagementComponent implements OnInit {
+  public user: string = '';
+  public healthStatus: GeneralEnvironmentStatus;
+  public allEnvironmentData: Array<EnvironmentModel>;
+  public anyEnvInProgress: boolean = false;
+  public notebookInProgress: boolean = false;
+
+  constructor(
+    public toastr: ToastrService,
+    public dialog: MatDialog,
+    private healthStatusService: HealthStatusService,
+    private backupService: BackupService,
+    private manageEnvironmentsService: ManageEnvironmentsService,
+    private userResourceService: UserResourceService,
+    private storageService: StorageService
+  ) { }
+
+  ngOnInit() {
+    this.buildGrid();
+    this.user = this.storageService.getUserName();
+  }
+
+  public buildGrid() {
+    this.getEnvironmentHealthStatus();
+  }
+
+  public manageEnvironmentAction($event) {
+    this.manageEnvironmentsService
+      .environmentManagement(
+        $event.environment.user,
+        $event.action,
+        $event.environment.name === 'edge node' ? 'edge' : $event.environment.name,
+        $event.resource ? $event.resource.computational_name : null
+      ).subscribe(
+        () => this.buildGrid(),
+        error => this.toastr.error('Environment management failed!', 'Oops!'));
+  }
+
+  showBackupDialog() {
+    this.dialog.open(BackupDilogComponent, { panelClass: 'modal-sm' });
+  }
+
+  showEndpointsDialog() {
+    this.dialog.open(EndpointsComponent, { panelClass: 'modal-xl-s' })
+      .afterClosed().subscribe(result => result && this.buildGrid());
+  }
+
+  openManageEnvironmentDialog() {
+    this.getActiveUsersList().subscribe(usersList => {
+      this.getTotalBudgetData().subscribe(
+        total => {
+          const dialogRef = this.dialog.open(ManageEnvironmentComponent, { data: { usersList, total }, panelClass: 'modal-xl-s'});
+          dialogRef.componentInstance.manageEnv.subscribe((data) => this.manageEnvironment(data));
+          dialogRef.afterClosed().subscribe(result => result && this.setBudgetLimits(result));
+        }, () => this.toastr.error('Failed users list loading!', 'Oops!'));
+    });
+  }
+
+  openSsnMonitorDialog() {
+    this.dialog.open(SsnMonitorComponent, { panelClass: 'modal-lg' });
+  }
+
+  isEnvironmentsInProgress(data): boolean {
+    return data.exploratory.some(el => {
+      return el.status === 'creating' || el.status === 'starting' ||
+        el.computational_resources.some(elem => elem.status === 'creating' || elem.status === 'starting' || elem.status === 'configuring');
+    });
+  }
+
+  isNotebookInProgress(data): boolean {
+    return data.exploratory.some(el => el.status === 'creating');
+  }
+
+  setBudgetLimits($event) {
+    this.healthStatusService.updateUsersBudget($event.users).subscribe((result: any) => {
+      this.healthStatusService.updateTotalBudgetData($event.total).subscribe((res: any) => {
+        result.status === HTTP_STATUS_CODES.OK
+          && res.status === HTTP_STATUS_CODES.NO_CONTENT
+          && this.toastr.success('Budget limits updated!', 'Success!');
+        this.buildGrid();
+      });
+    }, error => this.toastr.error(error.message, 'Oops!'));
+  }
+
+  manageEnvironment(event: { action: string, user: string }) {
+    this.healthStatusService.manageEnvironment(event.action, event.user)
+      .subscribe(res => {
+        this.getActiveUsersList().subscribe(usersList => {
+          // this.manageEnvironmentDialog.usersList = usersList;
+          this.toastr.success(`Action ${event.action} is processing!`, 'Processing!');
+          this.buildGrid();
+        });
+      },
+        error => this.toastr.error(error.message, 'Oops!'));
+  }
+
+  get creatingBackup(): boolean {
+    return this.backupService.inProgress;
+  }
+
+  private getExploratoryList() {
+    this.userResourceService.getUserProvisionedResources()
+      .subscribe((result) => {
+        this.anyEnvInProgress = this.isEnvironmentsInProgress(result);
+        this.notebookInProgress = this.isNotebookInProgress(result);
+      });
+  }
+
+  private getAllEnvironmentData() {
+    this.manageEnvironmentsService
+      .getAllEnvironmentData()
+      .subscribe((result: Array<EnvironmentModel>) => this.allEnvironmentData = this.loadEnvironmentList(result));
+  }
+
+  private loadEnvironmentList(data): Array<EnvironmentModel> {
+    if (data)
+      return data.map(value => new EnvironmentModel(
+        value.resource_name || value.resource_type,
+        value.status,
+        value.shape,
+        value.computational_resources,
+        value.user,
+        value.public_ip,
+        value.resource_type
+      ));
+  }
+
+  private getEnvironmentHealthStatus() {
+    this.healthStatusService
+      .getEnvironmentStatuses()
+      .subscribe((status: GeneralEnvironmentStatus) => {
+        this.healthStatus = status;
+        this.healthStatus.admin && this.getAllEnvironmentData();
+        this.getExploratoryList();
+      });
+  }
+
+  private getActiveUsersList() {
+    return this.healthStatusService.getActiveUsers();
+  }
+
+  private getTotalBudgetData() {
+    return this.healthStatusService.getTotalBudgetData();
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/management.model.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
similarity index 92%
rename from services/self-service/src/main/resources/webapp/src/app/management/management.model.ts
rename to services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
index 51ab721..641e098 100644
--- a/services/self-service/src/main/resources/webapp/src/app/management/management.model.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
@@ -32,9 +32,9 @@
 export class BackupOptionsModel {
   constructor(
     public configFiles: Array<string>,
-    public keys:  Array<string>,
-    public certificates:  Array<string>,
-    public jars:  Array<string>,
+    public keys: Array<string>,
+    public certificates: Array<string>,
+    public jars: Array<string>,
     public databaseBackup: boolean,
     public logsBackup: boolean
   ) { }
@@ -55,4 +55,5 @@
   billingQuoteUsed: number;
   list_resources: any;
   status: string;
+  projectAssigned: boolean;
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/ssn-monitor/ssn-monitor.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/management/ssn-monitor/ssn-monitor.component.html
similarity index 67%
rename from services/self-service/src/main/resources/webapp/src/app/management/ssn-monitor/ssn-monitor.component.html
rename to services/self-service/src/main/resources/webapp/src/app/administration/management/ssn-monitor/ssn-monitor.component.html
index 3d13266..30c818d 100644
--- a/services/self-service/src/main/resources/webapp/src/app/management/ssn-monitor/ssn-monitor.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/ssn-monitor/ssn-monitor.component.html
@@ -17,43 +17,44 @@
   ~ under the License.
   -->
 
-<modal-dialog #bindDialog modalClass="ssn-monitor-dialog modal-lg">
-  <modal-header>
+<div id="dialog-box" class="ssn-monitor-dialog">
+  <header class="dialog-header">
     <h4 class="modal-title">SSN Monitor</h4>
-  </modal-header>
-  <modal-content>
-    <div class="content-box" *ngIf="monitorData">
+    <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+  </header>
+  <div class="dialog-content">
+    <div class="content-box" *ngIf="data; else empty">
       <div class="ssn-info">
-        <mat-tab-group *ngIf="monitorData?.processorInfo" [dynamicHeight]="true">
+        <mat-tab-group *ngIf="data?.processorInfo" [dynamicHeight]="true">
           <mat-tab label="CPU">
             <div class="scrolling-content" id="scrolling">
               <mat-list-item class="list-header">
                 <div class="col">Name</div>
-                <div class="col">{{ monitorData.processorInfo.name }}</div>
+                <div class="col">{{ data.processorInfo.name }}</div>
               </mat-list-item>
               <mat-list-item class="list-header">
                 <div class="col">Vendor</div>
-                <div class="col">{{ monitorData.processorInfo.vendor }}</div>
+                <div class="col">{{ data.processorInfo.vendor }}</div>
               </mat-list-item>
               <mat-list-item class="list-header">
                 <div class="col">Logical Core Count</div>
-                <div class="col">{{ monitorData.processorInfo.logicalCoreCount }}</div>
+                <div class="col">{{ data.processorInfo.logicalCoreCount }}</div>
               </mat-list-item>
               <mat-list-item class="list-header">
                 <div class="col">Physical Core Count</div>
-                <div class="col">{{ monitorData.processorInfo.physicalCoreCount }}</div>
+                <div class="col">{{ data.processorInfo.physicalCoreCount }}</div>
               </mat-list-item>
               <mat-list-item class="list-header">
                 <div class="col">Current System Load</div>
-                <div class="col">{{ monitorData.processorInfo.currentSystemLoad /100 | percent:'1.0-2' }}</div>
+                <div class="col">{{ data.processorInfo.currentSystemLoad /100 | percent:'1.0-2' }}</div>
               </mat-list-item>
               <mat-list-item class="list-header">
                 <div class="col">System Load Average</div>
-                <div class="col">{{ monitorData.processorInfo.systemLoadAverage /100 | percent:'1.0-2' }}</div>
+                <div class="col">{{ data.processorInfo.systemLoadAverage /100 | percent:'1.0-2' }}</div>
               </mat-list-item>
               <mat-list-item class="list-header">
                 <div class="col">CPU 64 Bit</div>
-                <div class="col">{{ monitorData.processorInfo.cpu64Bit }}</div>
+                <div class="col">{{ data.processorInfo.cpu64Bit }}</div>
               </mat-list-item>
             </div>
           </mat-tab>
@@ -62,34 +63,34 @@
             <div class="scrolling-content" id="scrolling">
               <mat-list-item class="list-header">
                 <div class="col">Available Memory</div>
-                <div class="col">{{ convertSize(monitorData.memoryInfo.availableMemory) }}</div>
+                <div class="col">{{ convertSize(data.memoryInfo.availableMemory) }}</div>
               </mat-list-item>
               <mat-list-item class="list-header">
                 <div class="col">Total Memory</div>
-                <div class="col">{{ convertSize(monitorData.memoryInfo.totalMemory) }}</div>
+                <div class="col">{{ convertSize(data.memoryInfo.totalMemory) }}</div>
               </mat-list-item>
               <mat-list-item class="list-header">
                 <div class="col">Swap Total</div>
-                <div class="col">{{ convertSize(monitorData.memoryInfo.swapTotal) }}</div>
+                <div class="col">{{ convertSize(data.memoryInfo.swapTotal) }}</div>
               </mat-list-item>
               <mat-list-item class="list-header">
                 <div class="col">Swap Used</div>
-                <div class="col">{{ convertSize(monitorData.memoryInfo.swapUsed) }}</div>
+                <div class="col">{{ convertSize(data.memoryInfo.swapUsed) }}</div>
               </mat-list-item>
               <mat-list-item class="list-header">
                 <div class="col">Pages Page In</div>
-                <div class="col">{{ convertSize(monitorData.memoryInfo.pagesPageIn) }}</div>
+                <div class="col">{{ convertSize(data.memoryInfo.pagesPageIn) }}</div>
               </mat-list-item>
               <mat-list-item class="list-header">
                 <div class="col">Pages Page Out</div>
-                <div class="col">{{ convertSize(monitorData.memoryInfo.pagesPageOut) }}</div>
+                <div class="col">{{ convertSize(data.memoryInfo.pagesPageOut) }}</div>
               </mat-list-item>
             </div>
 
           </mat-tab>
           <mat-tab label="HDD">
             <div class="scrolling-content" id="scrolling">
-              <div *ngFor="let disk of monitorData.disksInfo; let i = index">
+              <div *ngFor="let disk of data.disksInfo; let i = index">
                 <mat-list-item>
                   <div class="col"><strong>Disk {{i +1}}</strong></div>
                 </mat-list-item>
@@ -106,12 +107,16 @@
           </mat-tab>
         </mat-tab-group>
         <div class="text-center">
-          <button type="button" class="butt" mat-raised-button (click)="close()">Close</button>
+          <button type="button" class="butt" mat-raised-button (click)="dialogRef.close()">Close</button>
         </div>
       </div>
-      <div class="info message" *ngIf="isEmpty(monitorData)">
+      <div class="info message" *ngIf="isEmpty(data)">
         No ssn monitor data available
       </div>
     </div>
-  </modal-content>
-</modal-dialog>
+    <ng-template #empty>
+      <p class="info message">Monitor data are not available</p>
+      <mat-progress-bar mode="indeterminate"></mat-progress-bar>
+    </ng-template>
+  </div>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/ssn-monitor/ssn-monitor.component.scss b/services/self-service/src/main/resources/webapp/src/app/administration/management/ssn-monitor/ssn-monitor.component.scss
similarity index 98%
rename from services/self-service/src/main/resources/webapp/src/app/management/ssn-monitor/ssn-monitor.component.scss
rename to services/self-service/src/main/resources/webapp/src/app/administration/management/ssn-monitor/ssn-monitor.component.scss
index 769fefe..9881165 100644
--- a/services/self-service/src/main/resources/webapp/src/app/management/ssn-monitor/ssn-monitor.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/ssn-monitor/ssn-monitor.component.scss
@@ -20,6 +20,7 @@
 .ssn-monitor-dialog {
   .content-box {
     padding-top: 10px !important;
+    position: relative;
   }
   .ssn-info {
     min-height: 400px;
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/ssn-monitor/ssn-monitor.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/ssn-monitor/ssn-monitor.component.ts
similarity index 68%
rename from services/self-service/src/main/resources/webapp/src/app/management/ssn-monitor/ssn-monitor.component.ts
rename to services/self-service/src/main/resources/webapp/src/app/administration/management/ssn-monitor/ssn-monitor.component.ts
index 25b2fa3..cbb7977 100644
--- a/services/self-service/src/main/resources/webapp/src/app/management/ssn-monitor/ssn-monitor.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/ssn-monitor/ssn-monitor.component.ts
@@ -17,8 +17,12 @@
  * under the License.
  */
 
-import { Component, OnInit, ViewChild, Output, EventEmitter, ViewEncapsulation } from '@angular/core';
-import { DICTIONARY } from './../../../dictionary/global.dictionary';
+import { Component, OnInit, ViewEncapsulation } from '@angular/core';
+import { MatDialogRef } from '@angular/material';
+import { ToastrService } from 'ngx-toastr';
+
+import { DICTIONARY } from '../../../../dictionary/global.dictionary';
+import { HealthStatusService } from '../../../core/services';
 
 @Component({
   selector: 'dlab-ssn-monitor',
@@ -30,19 +34,18 @@
   readonly DICTIONARY = DICTIONARY;
 
   public errorMessage: string = '';
-  public monitorData = {};
+  public data: any = null;
 
-  @ViewChild('bindDialog') bindDialog;
-  @Output() manageEnv: EventEmitter<{}> = new EventEmitter();
+  constructor(
+    public toastr: ToastrService,
+    public dialogRef: MatDialogRef<SsnMonitorComponent>,
+    private healthStatusService: HealthStatusService,
+  ) { }
 
-  ngOnInit() {}
-
-  public open(param, data): void {
-    this.monitorData = data || {};
-    this.bindDialog.open(param);
-  }
-  public close(param, data): void {
-    this.bindDialog.close();
+  ngOnInit() {
+    this.healthStatusService.getSsnMonitorData().subscribe(
+      monitorData => this.data = monitorData,
+      () => this.toastr.error('Failed ssn data loading!', 'Oops!'));
   }
 
   public isEmpty(obj) {
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
new file mode 100644
index 0000000..1c086d0
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/index.ts
@@ -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.
+ */
+
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+
+import { MaterialModule } from '../../shared/material.module';
+import { FormControlsModule } from '../../shared/form-controls';
+
+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';
+
+@NgModule({
+  imports: [
+    CommonModule,
+    FormsModule,
+    ReactiveFormsModule,
+    MaterialModule,
+    FormControlsModule
+  ],
+  declarations: [ProjectComponent, EditProjectComponent, ProjectFormComponent, ProjectListComponent],
+  entryComponents: [EditProjectComponent],
+  providers: [ProjectDataService],
+  exports: [ProjectComponent]
+})
+export class ProjectModule { }
\ No newline at end of file
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
new file mode 100644
index 0000000..ad877f2
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-data.service.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 { BehaviorSubject } from 'rxjs';
+
+import { ProjectService } from '../../core/services';
+import { Project } from './project.component';
+
+@Injectable()
+export class ProjectDataService {
+
+  _projects = new BehaviorSubject<any>(null);
+
+  constructor(private projectService: ProjectService) {
+    this.getProjectsList();
+  }
+
+  public updateProjects() {
+    this.getProjectsList();
+  }
+
+  private getProjectsList() {
+    this.projectService.getProjectsList().subscribe(
+      (response: Project[]) => this._projects.next(response));
+  }
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..052bcd8
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.html
@@ -0,0 +1,162 @@
+<!--
+  ~ 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.
+  -->
+
+<form [formGroup]="projectForm" novalidate>
+  <mat-horizontal-stepper #stepper class="stepper ani">
+    <mat-step>
+      <ng-template matStepLabel>Key upload</ng-template>
+      <section class="inner-step mat-reset upload-key">
+        <div class="form-block split">
+          <div class="row-wrap">
+            <div class="col">
+              <label class="control-label">
+                <span>Upload public key to start project creation</span>
+              </label>
+              <div>
+                <a href="#/help/publickeyguide" target="_blank">
+                  <small class="helper_instruction">
+                    <i class="material-icons">help_outline</i>Where can I get public key?</small>
+                </a>
+              </div>
+            </div>
+            <div class="col txt-r">
+              <span mat-raised-button class="butt butt-file" [ngClass]="{ 'not-allowed' : item }">
+                <span class="upload-icon"></span> Upload
+                <input (change)="onFileChange($event)" type="file" name="file" accept=".pub" />
+              </span>
+
+              <div *ngIf="keyLabel" class="m-bott-10 m-top-10 ellipsis" [class.danger_color]="!accessKeyValid">
+                {{ keyLabel }}</div>
+            </div>
+          </div>
+          <div class="text-center m-bott-10">
+            <button mat-raised-button type="button" class="butt" [disabled]="item" (click)="reset()">Clear</button>
+            <button mat-raised-button type="button" class="butt next" matStepperNext>Next
+              <i class="material-icons">keyboard_arrow_right</i></button>
+          </div>
+        </div>
+      </section>
+    </mat-step>
+    <mat-step>
+      <ng-template matStepLabel>Project</ng-template>
+      <section class="inner-step mat-reset">
+
+        <div class="form-block">
+          <div>
+            <div class="control-group">
+              <label class="label">Project name</label>
+              <div class="control">
+                <input type="text" formControlName="name" placeholder="Enter project name"
+                  (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" *ngIf="!projectForm?.controls.name.valid
+                  && !projectForm?.controls.name.hasError('duplication')
+                  && projectForm?.controls.name.dirty">Project name can only contain letters, numbers, hyphens and '_'
+                  but can not end with special characters
+                </span>
+              </div>
+            </div>
+            <div class="control-group">
+              <label class="label">Project tag</label>
+              <div class="control">
+                <input type="text" formControlName="tag" placeholder="dlab-{ project name }"
+                  [ngClass]="{ 'not-allowed' : item }">
+              </div>
+            </div>
+            <div class="control-group">
+              <div class="selector-wrapper">
+                <mat-form-field [ngClass]="{ 'not-allowed' : item }">
+                  <mat-select multiple formControlName="endpoints" placeholder="Select endpoints">
+                    <mat-option class="multiple-select" disabled>
+                      <a class="select ani" (click)="selectOptions(endpointsList, 'endpoints', 'all')">
+                        <i class="material-icons">playlist_add_check</i>&nbsp;All
+                      </a>
+                      <a class="deselect ani" (click)="selectOptions(endpointsList, 'endpoints')">
+                        <i class="material-icons">clear</i>&nbsp;None
+                      </a>
+                    </mat-option>
+                    <mat-option *ngFor="let endpoint of endpointsList" [value]="endpoint.name">
+                      {{ endpoint.name }}
+                    </mat-option>
+                    <mat-option *ngIf="!endpointsList.length" class="multiple-select empty ml-10" disabled>Endpoints
+                      list is empty</mat-option>
+                  </mat-select>
+                  <button class="caret">
+                    <i class="material-icons">keyboard_arrow_down</i>
+                  </button>
+                </mat-form-field>
+              </div>
+            </div>
+          </div>
+
+          <div class="text-center m-bott-10">
+            <button mat-raised-button type="button" class="butt" [disabled]="item" (click)="reset()">Clear</button>
+            <button mat-raised-button matStepperPrevious class="butt"><i
+                class="material-icons">keyboard_arrow_left</i>Back</button>
+            <button mat-raised-button type="button" class="butt next" matStepperNext>Next<i
+                class="material-icons">keyboard_arrow_right</i></button>
+          </div>
+        </div>
+
+      </section>
+    </mat-step>
+    <mat-step>
+      <ng-template matStepLabel>Groups</ng-template>
+      <div class="inner-step mat-reset">
+        <div class="form-block split">
+          <div class="control-group">
+            <div class="selector-wrapper">
+              <mat-form-field>
+                <mat-select multiple formControlName="groups" placeholder="Select user groups">
+                  <mat-option class="multiple-select" disabled>
+                    <a class="select ani" (click)="selectOptions(groupsList, 'groups', 'all')">
+                      <i class="material-icons">playlist_add_check</i>&nbsp;All
+                    </a>
+                    <a class="deselect ani" (click)="selectOptions(groupsList, 'groups')">
+                      <i class="material-icons">clear</i>&nbsp;None
+                    </a>
+                  </mat-option>
+                  <mat-option *ngFor="let group of groupsList" [value]="group">
+                    {{ group }}
+                  </mat-option>
+                  <mat-option *ngIf="!groupsList.length" class="multiple-select ml-10" disabled>Groups list is empty
+                  </mat-option>
+                </mat-select>
+                <button class="caret">
+                  <i class="material-icons">keyboard_arrow_down</i>
+                </button>
+              </mat-form-field>
+            </div>
+          </div>
+          <div class="text-center m-bott-10">
+            <button mat-raised-button type="button" class="butt" [disabled]="item" (click)="reset()">Clear</button>
+            <button mat-raised-button matStepperPrevious class="butt"><i
+                class="material-icons">keyboard_arrow_left</i>Back</button>
+            <button mat-raised-button type="button" class="butt butt-success" [disabled]="!projectForm.valid"
+              (click)="confirm(projectForm.value)">
+              <span *ngIf="item; else update">Update</span>
+              <ng-template #update>Create</ng-template>
+            </button>
+          </div>
+        </div>
+      </div>
+    </mat-step>
+  </mat-horizontal-stepper>
+</form>
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.scss b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.scss
similarity index 66%
copy from services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.scss
copy to services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.scss
index 6198578..8782430 100644
--- a/services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.scss
@@ -1,4 +1,4 @@
-/*!
+/*
  * 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
@@ -17,24 +17,33 @@
  * under the License.
  */
 
-.dashboard_table {
-  .th_user,
-  .th_name {
-    width: 20%;
+.form-block {
+  width: 600px;
+  &.split {
+    flex-direction: column;
+    display: flex;
+    justify-content: space-between;
+    height: 210px;
   }
-  .th_shape,
-  .th_status {
-    width: 12% !important;
-  }
-  .th_resources {
-    width: 33%;
-  }
-  .dashboard_table_body {
-    td:first-child {
-      cursor: default;
+  .mat-raised-button {
+    &.butt {
+      &.butt-success {
+        margin: 0;
+      }
     }
   }
+
+  .error {
+    position: absolute;
+    right: 0;
+    bottom: 2px;
+    font-family: 'Open Sans', sans-serif;
+    font-weight: 300;
+  }
 }
-.source .resource-wrap .resource-name .detailed-link {
-  cursor: default !important;
-}
+
+.upload-key {
+  .row-wrap {
+    padding: 35px 25px;
+  }
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..c56b84a
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.ts
@@ -0,0 +1,176 @@
+/*
+ * 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, Input, Output, EventEmitter, ViewChild, ChangeDetectorRef } from '@angular/core';
+import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+import { ToastrService } from 'ngx-toastr';
+import { Subscription } from 'rxjs';
+
+import { ProjectService, RolesGroupsService, EndpointService } from '../../../core/services';
+import { ProjectDataService } from '../project-data.service';
+import { CheckUtils, PATTERNS } from '../../../core/util';
+import { Project } from '../project.component';
+
+@Component({
+  selector: 'project-form',
+  templateUrl: './project-form.component.html',
+  styleUrls: ['./project-form.component.scss']
+})
+export class ProjectFormComponent implements OnInit {
+
+  public projectForm: FormGroup;
+  public groupsList: any = [];
+  public endpointsList: any = [];
+  public projectList: Project[] = [];
+  public accessKeyValid: boolean;
+  public keyLabel: string = '';
+
+  @Input() item: any;
+  @Output() update: EventEmitter<{}> = new EventEmitter();
+  @ViewChild('stepper') stepper;
+
+  private subscriptions: Subscription = new Subscription();
+
+  constructor(
+    public toastr: ToastrService,
+    private _fb: FormBuilder,
+    private projectService: ProjectService,
+    private projectDataService: ProjectDataService,
+    private rolesService: RolesGroupsService,
+    private endpointService: EndpointService,
+    private cd: ChangeDetectorRef
+  ) { }
+
+  ngOnInit() {
+    this.initFormModel();
+    this.getGroupsData();
+    this.getEndpointsData();
+
+    this.subscriptions.add(this.projectDataService._projects.subscribe(
+      (value: Project[]) => {
+        if (value) this.projectList = value;
+      }));
+    if (this.item) {
+      this.editSpecificProject(this.item);
+      this.stepper.selectedIndex = 2;
+    }
+  }
+
+  public confirm(data) {
+    if (this.item) {
+      this.projectService.updateProject(data).subscribe(() => {
+        this.toastr.success('Project updated successfully!', 'Success!');
+        this.update.emit();
+      }, error => this.toastr.error(error.message || 'Project update failed!', 'Oops!'));
+    } else {
+      this.projectService.createProject(data).subscribe(() => {
+        this.toastr.success('Project created successfully!', 'Success!');
+        this.projectDataService.updateProjects();
+        this.update.emit();
+        this.reset();
+      }, error => this.toastr.error(error.message || 'Project creation failed!', 'Oops!'));
+    }
+  }
+
+  public reset() {
+    this.keyLabel = '';
+    this.initFormModel();
+  }
+
+  public generateProjectTag($event) {
+    let user_tag = `dlab-${$event.target.value}`;
+    this.projectForm.controls.tag.setValue(user_tag.toLowerCase());
+  }
+
+  public onFileChange($event) {
+    const reader = new FileReader();
+    const files = $event.target.files;
+
+    if (files && files.length) {
+      const [file] = $event.target.files;
+      reader.readAsBinaryString(file);
+
+      reader.onload = () => {
+        this.projectForm.patchValue({
+          key: reader.result
+        });
+
+        this.accessKeyValid = this.isValidKey(file.name);
+        this.keyLabel = this.getLabel(file);
+        $event.target.value = '';
+        this.cd.markForCheck();
+      };
+    }
+  }
+
+  public selectOptions(list, key, select?) {
+    let filter = key === 'endpoints' ? list.map(el => el.name) : list;
+    this.projectForm.controls[key].setValue(select ? filter : []);
+  }
+
+  private initFormModel(): void {
+    this.projectForm = this._fb.group({
+      'key': ['', Validators.required],
+      'name': ['', Validators.compose([Validators.required, Validators.pattern(PATTERNS.namePattern), this.checkDuplication.bind(this)])],
+      'endpoints': [[], Validators.required],
+      'tag': ['', Validators.compose([Validators.required, Validators.pattern(PATTERNS.namePattern)])],
+      'groups': [[], Validators.required]
+    });
+  }
+
+  public editSpecificProject(item: Project) {
+
+    this.projectForm = this._fb.group({
+      'key': [''],
+      'name': [item.name, Validators.required],
+      'endpoints': [item.endpoints],
+      'tag': [item.tag, Validators.required],
+      'groups': [item.groups, Validators.required]
+    });
+  }
+
+  private getLabel(file: File): string {
+    return file ? !this.accessKeyValid ? 'Public key is required.' : file.name : '';
+  }
+
+  private isValidKey(value): boolean {
+    return value.toLowerCase().endsWith('.pub');
+  }
+
+  private getGroupsData() {
+    this.rolesService.getGroupsData().subscribe(
+      (list: any) => this.groupsList = list.map(el => el.group),
+      error => this.toastr.error(error.message, 'Oops!'));
+  }
+
+  private getEndpointsData() {
+    this.endpointService.getEndpointsData().subscribe(
+      list => this.endpointsList = list,
+      error => this.toastr.error(error.message, 'Oops!'));
+  }
+
+  private checkDuplication(control) {
+    if (control.value) {
+      for (let index = 0; index < this.projectList.length; index++) {
+        if (CheckUtils.delimitersFiltering(control.value) === CheckUtils.delimitersFiltering(this.projectList[index].name))
+          return { duplication: true };
+      }
+    }
+  }
+}
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
new file mode 100644
index 0000000..01d858f
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.html
@@ -0,0 +1,79 @@
+<!--
+  ~ 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 mat-table [dataSource]="dataSource" class="projects-table mat-elevation-z6 selection">
+  <ng-container matColumnDef="name">
+    <th mat-header-cell *matHeaderCellDef class="name"> Project name </th>
+    <td mat-cell *matCellDef="let element"> {{element.name}} </td>
+  </ng-container>
+
+  <ng-container matColumnDef="endpoints">
+    <th mat-header-cell *matHeaderCellDef class="endpoints"> Endpoints </th>
+    <td mat-cell *matCellDef="let element">
+      <mat-chip-list>
+        <mat-chip *ngFor="let endpoint of element.endpoints">{{ endpoint }}</mat-chip>
+      </mat-chip-list>
+    </td>
+  </ng-container>
+
+  <ng-container matColumnDef="status">
+    <th mat-header-cell *matHeaderCellDef class="status"> Status </th>
+    <td mat-cell *matCellDef="let element" class="status" ngClass="{{ element.status.toLowerCase() || '' }}">
+      {{ element.status.toLowerCase() }}
+    </td>
+  </ng-container>
+
+  <ng-container matColumnDef="groups">
+    <th mat-header-cell *matHeaderCellDef class="groups"> Groups </th>
+    <td mat-cell *matCellDef="let element">
+      <mat-chip-list>
+        <mat-chip *ngFor="let group of element.groups">{{ group }}</mat-chip>
+      </mat-chip-list>
+    </td>
+  </ng-container>
+
+  <ng-container matColumnDef="actions">
+    <th mat-header-cell *matHeaderCellDef class="project-actions"></th>
+    <td mat-cell *matCellDef="let element" class="project-actions">
+      <span>
+        <a class="start-stop-action">
+          <mat-icon *ngIf="element.status === 'ACTIVE'" (click)="toggleProjectStatus(element, 'stop')">
+            pause_circle_outline
+          </mat-icon>
+          <mat-icon *ngIf="element.status === 'STOPPED'" (click)="toggleProjectStatus(element, 'start')">
+            play_circle_outline
+          </mat-icon>
+        </a>
+      </span>
+      <span [ngClass]="{'not-active' : element.status !== 'ACTIVE' }">
+        <a [ngClass]="{'not-allowed' : element.status !== 'ACTIVE' }"
+          (click)="element.status === 'ACTIVE' && editProject(element)">
+          <mat-icon>mode_edit</mat-icon>
+        </a>
+      </span>
+      <span (click)="deleteProject(element)">
+        <mat-icon>delete_forever</mat-icon>
+      </span>
+    </td>
+
+  </ng-container>
+
+  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+  <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
+</table>
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.scss b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.scss
similarity index 62%
copy from services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.scss
copy to services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.scss
index 6198578..bd3ebdd 100644
--- a/services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.scss
@@ -1,4 +1,4 @@
-/*!
+/*
  * 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
@@ -17,24 +17,44 @@
  * under the License.
  */
 
-.dashboard_table {
-  .th_user,
-  .th_name {
-    width: 20%;
+table {
+  width: 100%;
+
+  .name {
+    width: 25%;
   }
-  .th_shape,
-  .th_status {
-    width: 12% !important;
+
+  .endpoints {
+    width: 25%;
+    padding: 0 10px;
   }
-  .th_resources {
-    width: 33%;
+
+  .groups {
+    width: 25%;
+    padding: 0 10px;
   }
-  .dashboard_table_body {
-    td:first-child {
-      cursor: default;
+
+  .status {
+    width: 15%;
+  }
+
+  .project-actions {
+    color: #607d8b;
+    width: 10%;
+    text-align: center;
+
+    span {
+      transition: all .5s ease-in-out;
+      cursor: pointer;
+
+      .mat-icon {
+        font-size: 18px;
+        padding-top: 5px;
+      }
+
+      &:hover {
+        color: darken(#607d8b, 10%);
+      }
     }
   }
 }
-.source .resource-wrap .resource-name .detailed-link {
-  cursor: default !important;
-}
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
new file mode 100644
index 0000000..1dd8210
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.ts
@@ -0,0 +1,72 @@
+/*
+ * 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, Output, EventEmitter, OnDestroy } from '@angular/core';
+import { ToastrService } from 'ngx-toastr';
+import { MatTableDataSource } from '@angular/material';
+import { Subscription } from 'rxjs';
+
+import { ProjectDataService } from '../project-data.service';
+import { ProjectService } from '../../../core/services';
+import { Project } from '../project.component';
+
+@Component({
+  selector: 'project-list',
+  templateUrl: './project-list.component.html',
+  styleUrls: ['./project-list.component.scss']
+})
+export class ProjectListComponent implements OnInit, OnDestroy {
+
+  displayedColumns: string[] = ['name', 'status', 'endpoints', 'groups', 'actions'];
+  dataSource: Project[] | any = [];
+  @Output() editItem: EventEmitter<{}> = new EventEmitter();
+  @Output() deleteItem: EventEmitter<{}> = new EventEmitter();
+  @Output() toggleStatus: EventEmitter<{}> = new EventEmitter();
+
+  private subscriptions: Subscription = new Subscription();
+
+  constructor(
+    public toastr: ToastrService,
+    private projectDataService: ProjectDataService,
+    private projectService: ProjectService
+  ) { }
+
+
+  ngOnInit() {
+    this.subscriptions.add(this.projectDataService._projects.subscribe((value: Project[]) => {
+      if (value) this.dataSource = new MatTableDataSource(value);
+    }));
+  }
+
+  ngOnDestroy() {
+    this.subscriptions.unsubscribe();
+  }
+
+  public toggleProjectStatus(project, action) {
+    this.toggleStatus.emit({ project, action });
+  }
+
+  public editProject(item: Project[]) {
+    this.editItem.emit(item);
+  }
+
+  public deleteProject(item: Project[]) {
+    this.deleteItem.emit(item);
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.html
new file mode 100644
index 0000000..2e01d31
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.html
@@ -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.
+  -->
+
+
+<div *ngIf="projectList" class="base-retreat">
+  <div class="sub-nav">
+    <div>
+      <button mat-raised-button class="butt butt-create" (click)="createProject()" [disabled]="!projectList.length">
+        <i class="material-icons">add</i>Create new
+      </button>
+    </div>
+    <div>
+      <button mat-raised-button class="butt" (click)="refreshGrid()" [hidden]="!projectList.length">
+        <i class="material-icons">autorenew</i>Refresh
+      </button>
+    </div>
+  </div>
+
+  <mat-divider></mat-divider>
+
+  <mat-card class="project-form" *ngIf="!projectList.length">
+    <project-form></project-form>
+  </mat-card>
+
+  <div [hidden]="!projectList.length">
+    <project-list (editItem)="editProject($event)" (deleteItem)="deleteProject($event)"
+      (toggleStatus)="toggleStatus($event)">
+    </project-list>
+  </div>
+</div>
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
new file mode 100644
index 0000000..261b4d9
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.ts
@@ -0,0 +1,143 @@
+/*
+ * 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, OnDestroy, Inject } from '@angular/core';
+import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
+import { Subscription } from 'rxjs';
+
+import { ProjectDataService } from './project-data.service';
+import { HealthStatusService, ProjectService } from '../../core/services';
+import { NotificationDialogComponent } from '../../shared/modal-dialog/notification-dialog';
+
+export interface Project {
+  name: string;
+  endpoints: string[];
+  tag: string;
+  groups: string[];
+}
+
+@Component({
+  selector: 'dlab-project',
+  templateUrl: './project.component.html'
+})
+export class ProjectComponent implements OnInit, OnDestroy {
+  projectList: Project[] = [];
+  healthStatus: any;
+
+  private subscriptions: Subscription = new Subscription();
+
+  constructor(
+    public dialog: MatDialog,
+    private projectService: ProjectService,
+    private projectDataService: ProjectDataService,
+    private healthStatusService: HealthStatusService
+  ) { }
+
+  ngOnInit() {
+    this.getEnvironmentHealthStatus();
+    this.subscriptions.add(this.projectDataService._projects.subscribe(
+      (value: Project[]) => {
+        if (value) this.projectList = value;
+      }));
+  }
+
+  ngOnDestroy() {
+    this.subscriptions.unsubscribe();
+  }
+
+  refreshGrid() {
+    this.projectDataService.updateProjects();
+  }
+
+  createProject() {
+    console.log('create');
+
+    if (this.projectList.length)
+      this.dialog.open(EditProjectComponent, { data: { action: 'create', item: null }, panelClass: 'modal-xl-s' })
+        .afterClosed().subscribe(() => {
+          console.log('Create project');
+        });
+  }
+
+  public editProject($event) {
+    this.dialog.open(EditProjectComponent, { data: { action: 'edit', item: $event }, panelClass: 'modal-xl-s' })
+      .afterClosed().subscribe(() => {
+        this.refreshGrid();
+      });
+  }
+
+  public deleteProject($event) {
+    this.dialog.open(NotificationDialogComponent, { data: { type: 'confirmation', item: $event }, panelClass: 'modal-sm' })
+      .afterClosed().subscribe(result => {
+        result && this.projectService.deleteProject($event.name).subscribe(() => {
+          this.refreshGrid();
+        });
+      });
+  }
+
+  public toggleStatus($event) {
+    const data = { 'project_name': $event.project.name };
+
+    if ($event.action === 'stop') {
+      this.dialog.open(NotificationDialogComponent, { data: { type: 'confirmation', item: $event.project, action: 'stopped' }, panelClass: 'modal-sm' })
+        .afterClosed().subscribe(result => {
+          result && this.toggleStatusRequest(data, $event.action);
+        });
+    } else {
+      this.toggleStatusRequest(data, $event.action);
+    }
+  }
+
+  private toggleStatusRequest(data, action) {
+    this.projectService.toggleProjectStatus(data, action).subscribe(res => this.refreshGrid());
+  }
+
+  private getEnvironmentHealthStatus() {
+    this.healthStatusService.getEnvironmentHealthStatus()
+      .subscribe((result: any) => this.healthStatus = result);
+  }
+}
+
+@Component({
+  selector: 'edit-project',
+  template: `
+    <div id="dialog-box" class="edit-form">
+      <div class="dialog-header">
+        <h4 class="modal-title">
+          <span *ngIf="data?.action === 'create'">Create new project</span>
+          <span *ngIf="data?.action === 'edit'">Edit {{ data.item.name }}</span>
+        </h4>
+        <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+      </div>
+      <div mat-dialog-content class="content project-form">
+        <project-form [item]="data.item" (update)="dialogRef.close(true)"></project-form>
+      </div>
+    </div>
+  `,
+  styles: [`
+    .content { color: #718ba6; padding: 0; font-size: 14px; font-weight: 400; margin: 0; overflow: hidden; }
+    .edit-form { height: 380px; overflow: hidden; }
+  `]
+})
+export class EditProjectComponent {
+  constructor(
+    public dialogRef: MatDialogRef<EditProjectComponent>,
+    @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/management/manage-roles-groups/group-name-validarion.directive.ts b/services/self-service/src/main/resources/webapp/src/app/administration/roles/group-name-validarion.directive.ts
similarity index 100%
rename from services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/group-name-validarion.directive.ts
rename to services/self-service/src/main/resources/webapp/src/app/administration/roles/group-name-validarion.directive.ts
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/exploratory-environment-create-dialog/index.ts b/services/self-service/src/main/resources/webapp/src/app/administration/roles/index.ts
similarity index 65%
copy from services/self-service/src/main/resources/webapp/src/app/resources/exploratory/exploratory-environment-create-dialog/index.ts
copy to services/self-service/src/main/resources/webapp/src/app/administration/roles/index.ts
index 5bed5dc..d0c57cc 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/exploratory-environment-create-dialog/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/roles/index.ts
@@ -21,21 +21,21 @@
 import { CommonModule } from '@angular/common';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 
-import { MaterialModule } from '../../../shared/material.module';
-import { ModalModule } from '../../../shared';
-import { FormControlsModule } from '../../../shared/form-controls';
-import { ExploratoryEnvironmentCreateDialogComponent } from './exploratory-environment-create-dialog.component';
+import { MaterialModule } from '../../shared/material.module';
+import { FormControlsModule } from '../../shared/form-controls';
+import { RolesComponent, ConfirmDeleteUserAccountDialogComponent } from './roles.component';
+import { GroupNameValidationDirective } from './group-name-validarion.directive';
 
 @NgModule({
   imports: [
     CommonModule,
-    ModalModule,
     FormsModule,
     ReactiveFormsModule,
-    FormControlsModule,
-    MaterialModule
+    MaterialModule,
+    FormControlsModule
   ],
-  declarations: [ExploratoryEnvironmentCreateDialogComponent],
-  exports: [ExploratoryEnvironmentCreateDialogComponent]
+  declarations: [RolesComponent, ConfirmDeleteUserAccountDialogComponent, GroupNameValidationDirective],
+  entryComponents: [ConfirmDeleteUserAccountDialogComponent],
+  exports: [RolesComponent]
 })
-export class ExploratoryEnvironmentCreateDialogModule {}
+export class RolesModule { }
\ No newline at end of file
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
new file mode 100644
index 0000000..fe499ae
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.html
@@ -0,0 +1,172 @@
+<!--
+  ~ 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="manage-roles base-retreat">
+  <div class="sub-nav">
+    <div>
+      <button mat-raised-button class="butt add-group" (click)="stepperView = !stepperView">
+        <i class="material-icons">people_outline</i>Add group
+      </button>
+    </div>
+    <div></div>
+  </div>
+
+  <mat-card *ngIf="stepperView" class="m-top-10">
+    <mat-horizontal-stepper #stepper  class="stepper ani">
+      <mat-step>
+        <ng-template matStepLabel>Groups</ng-template>
+        <div class="inner-step mat-reset">
+          <input [validator]="groupValidarion()" type="text" placeholder="Enter group name" [(ngModel)]="setupGroup"
+            #setupGroupName="ngModel">
+          <div class="danger_color" *ngIf="setupGroupName.errors?.patterns && setupGroupName.dirty">Group name can only
+            contain letters, numbers, hyphens and '_'</div>
+          <div class="danger_color" *ngIf="setupGroupName.errors?.duplicate && setupGroupName.dirty">Group name already
+            exists</div>
+        </div>
+        <div class="text-center m-bott-10">
+          <button mat-raised-button (click)="resetDialog()" class="butt">Cancel</button>
+          <button mat-raised-button matStepperNext class="butt">Next<i
+              class="material-icons">keyboard_arrow_right</i></button>
+        </div>
+      </mat-step>
+      <mat-step>
+        <ng-template matStepLabel>Roles</ng-template>
+        <div class="inner-step mat-reset">
+          <div class="selector-wrapper">
+            <mat-form-field>
+              <mat-select multiple [compareWith]="compareObjects" name="roles" [(value)]="setupRoles"
+                placeholder="Select roles">
+                <mat-option class="multiple-select" disabled>
+                  <a class="select ani" (click)="selectAllOptions(setupRoles, rolesList)">
+                    <i class="material-icons">playlist_add_check</i>&nbsp;All
+                  </a>
+                  <a class="deselect ani" (click)="selectAllOptions(setupRoles)">
+                    <i class="material-icons">clear</i>&nbsp;None
+                  </a>
+                </mat-option>
+                <mat-option *ngFor="let role of rolesList" [value]="role">
+                  {{ role }}
+                </mat-option>
+              </mat-select>
+              <button class="caret">
+                <i class="material-icons">keyboard_arrow_down</i>
+              </button>
+            </mat-form-field>
+          </div>
+        </div>
+        <div class="text-center m-bott-10">
+          <button mat-raised-button matStepperPrevious class="butt"><i
+              class="material-icons">keyboard_arrow_left</i>Back</button>
+          <button mat-raised-button (click)="resetDialog()" class="butt">Cancel</button>
+          <button mat-raised-button matStepperNext class="butt">Next<i
+              class="material-icons">keyboard_arrow_right</i></button>
+        </div>
+      </mat-step>
+      <mat-step>
+        <ng-template matStepLabel>Users</ng-template>
+        <div class="inner-step mat-reset">
+          <input type="text" placeholder="Enter user login" [(ngModel)]="setupUser">
+        </div>
+        <div class="text-center m-bott-10">
+          <button mat-raised-button matStepperPrevious class="butt"><i
+              class="material-icons">keyboard_arrow_left</i>Back</button>
+          <button mat-raised-button (click)="resetDialog()" class="butt">Cancel</button>
+          <button mat-raised-button (click)="manageAction('create', 'group')" class="butt butt-success"
+            [disabled]="!setupGroup || setupGroupName.errors?.pattern || !setupRoles.length > 0">Create</button>
+        </div>
+      </mat-step>
+    </mat-horizontal-stepper>
+  </mat-card>
+  <mat-divider></mat-divider>
+
+  <div *ngIf="groupsData.length" class="ani">
+    <table mat-table [dataSource]="groupsData" class="projects-table mat-elevation-z6">
+      <ng-container matColumnDef="name">
+        <th mat-header-cell *matHeaderCellDef class="name"> Group name </th>
+        <td mat-cell *matCellDef="let element"> {{element.group}} </td>
+      </ng-container>
+
+      <ng-container matColumnDef="roles">
+        <th mat-header-cell *matHeaderCellDef class="roles"> Roles </th>
+        <td mat-cell *matCellDef="let element" class="roles mat-reset">
+          <div class="selector-wrapper-edit">
+            <mat-form-field>
+              <mat-select multiple [compareWith]="compareObjects" name="selected_roles" [(value)]="element.selected_roles"
+                placeholder="Select roles">
+                <mat-option class="multiple-select" disabled>
+                  <a class="select ani" (click)="selectAllOptions(element, rolesList, 'selected_roles')">
+                    <i class="material-icons">playlist_add_check</i>&nbsp;All
+                  </a>
+                  <a class="deselect ani" (click)="selectAllOptions(element, null, 'selected_roles')">
+                    <i class="material-icons">clear</i>&nbsp;None
+                  </a>
+                </mat-option>
+                <mat-option *ngFor="let role of rolesList" [value]="role">
+                  {{ role }}
+                </mat-option>
+              </mat-select>
+              <button class="caret ani">
+                <i class="material-icons">keyboard_arrow_down</i>
+              </button>
+            </mat-form-field>
+          </div>
+        </td>
+      </ng-container>
+
+      <ng-container matColumnDef="users">
+        <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" pattern="[@.-_0-9a-zA-Z]"
+              (keydown.enter)="addUser(user.value, element); user.value = ''">
+            <button mat-icon-button matSuffix (click)="addUser(user.value, element); user.value = ''">
+              <mat-icon>person_add</mat-icon>
+            </button>
+          </mat-form-field>
+          <div class="list-selected list-container ani">
+            <mat-chip-list>
+              <mat-chip *ngFor="let user of element.users">
+                {{ user }}
+                <a class="material-icons" (click)="removeUser(element.users, user)">clear</a>
+              </mat-chip>
+            </mat-chip-list>
+          </div>
+        </td>
+      </ng-container>
+
+      <ng-container matColumnDef="actions">
+        <th mat-header-cell *matHeaderCellDef class="actions"></th>
+        <td mat-cell *matCellDef="let element" class="actions">
+          <span (click)="manageAction('delete', 'group', element)" class="reset ani">
+            <mat-icon>delete_forever</mat-icon>
+          </span>
+          <span class="apply ani" matTooltip="Group cannot be updated without any selected role"
+                matTooltipPosition="above" [matTooltipDisabled]="element.selected_roles.length > 0"
+                [ngClass]="{ 'not-allowed' : !element.selected_roles.length }" (click)="manageAction('update', 'group', element)">
+            <mat-icon>done</mat-icon>
+          </span>
+        </td>
+      </ng-container>
+
+      <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
+      <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
+    </table>
+
+  </div>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/manage-roles-groups.component.scss b/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.scss
similarity index 88%
rename from services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/manage-roles-groups.component.scss
rename to services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.scss
index b28c061..aef38c3 100644
--- a/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/manage-roles-groups.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.scss
@@ -17,7 +17,9 @@
  * under the License.
  */
 
-::ng-deep .mat-option:first-child .mat-pseudo-checkbox { display: none; }
+::ng-deep .mat-option:first-child .mat-pseudo-checkbox {
+  display: none;
+}
 
 .caret {
   width: 40px;
@@ -29,27 +31,28 @@
   right: 0;
   top: 0px;
   height: 36px;
+  line-height: 1;
   cursor: pointer;
+
   &.not-allowed {
     background-color: #dcdcdc;
   }
 }
 
-
 .content-box {
   padding: 20px 30px 35px;
   height: 85vh;
   overflow-y: auto;
 }
+
 .no-details {
   color: #d8d8d8;
 }
-.mat-divider {
-  margin: 10px 0;
-}
+
 .stepper {
   height: 190px;
   margin-top: 10px;
+
   .inner-step {
     height: 70px;
     padding: 5px;
@@ -57,16 +60,19 @@
     justify-content: center;
     flex-direction: column;
     text-align: center;
+
     input {
       width: 490px;
       align-self: center;
     }
+
     .caret {
       i {
         margin-top: 3px;
       }
     }
   }
+
   .text-center {
     button {
       &:not(:last-child) {
@@ -75,6 +81,7 @@
     }
   }
 }
+
 .selector-wrapper {
   display: flex;
   align-self: center;
@@ -85,38 +92,47 @@
   font-size: 15px;
   font-weight: 300;
   box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
+
   mat-form-field {
     width: 100%;
+
     .mat-form-field-wrapper {
       padding-bottom: 0;
     }
+
     .mat-icon {
       font-size: 20px;
     }
   }
+
   .dropdown-multiselect {
     width: 100% !important;
-    > button {
+
+    >button {
       padding: 6px 22px;
     }
   }
 }
+
 .list-header {
   padding: 0 15px;
 }
+
 .scrolling-content {
   max-height: 450px;
   overflow-x: hidden;
   overflow-y: auto;
   display: block;
   padding: 15px 5px;
+
   &.stepper-opened {
     height: 250px;
   }
 }
+
 .roles {
   width: 30%;
-  padding: 0 10px;
+
   .selector-wrapper-edit {
     position: relative;
     display: flex;
@@ -125,14 +141,17 @@
     padding-left: 10px;
     background: #fff;
     box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
+
     multi-select-dropdown {
       width: 100%;
+
       .dropdown-multiselect {
-        > button {
+        >button {
           padding: 8px 22px 5px;
         }
       }
     }
+
     .caret {
       &:hover {
         box-shadow: 0 3px 1px -10px rgba(0, 0, 0, 0.2), 0 2px 1px 0 rgba(0, 0, 0, 0.17), 0 1px 5px 0 rgba(0, 0, 0, 0.12)
@@ -140,13 +159,16 @@
     }
   }
 }
+
 .groups {
   width: 20%;
 }
+
 .users {
   width: 30%;
   padding: 0 10px;
 }
+
 .users-list {
   padding: 5px 10px;
   font-family: 'Open Sans', sans-serif;
@@ -154,34 +176,40 @@
   font-weight: 300;
   color: #577289;
   position: relative;
+
   i {
     color: #FF5722;
     font-size: 18px;
     cursor: pointer;
   }
+
   .list-selected {
     width: 100%;
     margin-top: 50px;
     height: inherit;
     min-height: 0;
-    overflow-y: hidden;
+    overflow: hidden;
   }
 }
+
 .expanded-panel {
   display: flex;
   align-items: flex-end;
+
   .add-input-block {
     display: flex;
     height: 36px;
     padding-right: 0;
     outline: none;
     box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
+
     input {
       height: 36px;
       padding: 0;
       padding-left: 10px;
       width: 170px;
     }
+
     .caret {
       width: 50px;
     }
@@ -202,6 +230,7 @@
   .mat-step-icon {
     background-color: #36afd5 !important;
   }
+
   .mat-step-label {
     font-family: 'Open Sans', sans-serif;
     font-size: 16px;
@@ -214,10 +243,12 @@
     .actions {
       padding: 10px 0;
     }
+
     &.filter-row {
       .actions {
         button {
           background: none;
+
           .mid {
             vertical-align: sub;
           }
@@ -225,13 +256,14 @@
       }
     }
   }
+
   .th_actions {
     width: 10%;
   }
 }
 
 .mat-chip:not(.mat-basic-chip) {
-  transition: box-shadow 280ms cubic-bezier(.4,0,.2,1);
+  transition: box-shadow 280ms cubic-bezier(.4, 0, .2, 1);
   padding: 7px 0 7px 10px;
   border-radius: 24px;
   cursor: default;
@@ -242,12 +274,13 @@
   max-width: 100%;
   overflow: hidden;
   text-overflow: ellipsis;
-  margin: 2px !important;
 }
+
 mat-chip.mat-chip a {
   position: absolute;
   right: 15px;
 }
+
 mat-form-field.chip-list {
   &.mat-form-field {
     position: absolute;
@@ -265,9 +298,11 @@
     }
   }
 }
+
 .multiple-select {
   border-bottom: 1px solid #dedbdb;
   padding: 0;
+
   a {
     display: inline-block;
     width: 50%;
@@ -275,14 +310,17 @@
     vertical-align: middle;
     color: #575757;
     cursor: pointer;
+
     i {
       vertical-align: sub;
       font-size: 20px;
     }
+
     &:hover {
       color: #4eaf3e;
       background: #f9fafb;
     }
+
     &.deselect {
       &:hover {
         color: #f1696e;
@@ -290,3 +328,39 @@
     }
   }
 }
+
+table {
+  width: 100%;
+
+  .name {
+    width: 15%;
+  }
+
+  .roles {
+    width: 30%;
+  }
+
+  .users {
+    width: 40%;
+  }
+
+  .actions {
+    color: #607d8b;
+    width: 10%;
+    text-align: center;
+
+    span {
+      transition: all .5s ease-in-out;
+      cursor: pointer;
+
+      .mat-icon {
+        font-size: 18px;
+        padding-top: 12px;
+      }
+
+      &:hover {
+        color: darken(#607d8b, 10%);
+      }
+    }
+  }
+}
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
new file mode 100644
index 0000000..eb5d902
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/roles/roles.component.ts
@@ -0,0 +1,244 @@
+/*
+ * 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, Output, EventEmitter, Inject } from '@angular/core';
+import { ValidatorFn, FormControl } from '@angular/forms';
+import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
+import { ToastrService } from 'ngx-toastr';
+
+import { RolesGroupsService, HealthStatusService } from '../../core/services';
+import { CheckUtils } from '../../core/util';
+import { DICTIONARY } from '../../../dictionary/global.dictionary';
+
+@Component({
+  selector: 'dlab-roles',
+  templateUrl: './roles.component.html',
+  styleUrls: ['../../resources/resources-grid/resources-grid.component.css', './roles.component.scss']
+})
+export class RolesComponent implements OnInit {
+  readonly DICTIONARY = DICTIONARY;
+
+  public groupsData: Array<any> = [];
+  public roles: Array<any> = [];
+  public rolesList: Array<string> = [];
+  public setupGroup: string = '';
+  public setupUser: string = '';
+  public manageUser: string = '';
+  public setupRoles: Array<string> = [];
+  public updatedRoles: Array<string> = [];
+  public healthStatus: any;
+  public delimitersRegex = /[-_]?/g;
+  public groupnamePattern = new RegExp(/^[a-zA-Z0-9_\-]+$/);
+
+  stepperView: boolean = false;
+  displayedColumns: string[] = ['name', 'roles', 'users', 'actions'];
+  @Output() manageRolesGroupAction: EventEmitter<{}> = new EventEmitter();
+
+  constructor(
+    public toastr: ToastrService,
+    public dialog: MatDialog,
+    private rolesService: RolesGroupsService,
+    private healthStatusService: HealthStatusService
+  ) { }
+
+  ngOnInit() {
+    this.openManageRolesDialog();
+    this.getEnvironmentHealthStatus();
+  }
+
+  openManageRolesDialog() {
+    this.rolesService.getGroupsData().subscribe(groups => {
+      this.rolesService.getRolesData().subscribe(
+        (roles: any) => {
+          this.roles = roles;
+          this.rolesList = roles.map(role => role.description);
+          this.updateGroupData(groups);
+
+          this.stepperView = false;
+        },
+        error => this.toastr.error(error.message, 'Oops!'));
+    },
+      error => this.toastr.error(error.message, 'Oops!'));
+  }
+
+  getGroupsData() {
+    this.rolesService.getGroupsData().subscribe(
+      list => this.updateGroupData(list),
+      error => this.toastr.error(error.message, 'Oops!'));
+  }
+
+  public selectAllOptions(item, values, byKey?) {
+    byKey ? (item[byKey] = values ? values : []) : this.setupRoles = values ? values : [];
+  }
+
+  public manageAction(action: string, type: string, item?: any, value?) {
+    if (action === 'create') {
+      this.manageRolesGroups(
+        {
+          action, type, value: {
+            name: this.setupGroup,
+            users: this.setupUser ? this.setupUser.split(',').map(elem => elem.trim()) : [],
+            roleIds: this.extractIds(this.roles, this.setupRoles)
+          }
+        });
+      this.stepperView = false;
+    } else if (action === 'delete') {
+      const data = (type === 'users') ? { group: item.group, user: value } : { group: item.group, id: item };
+      const dialogRef: MatDialogRef<ConfirmDeleteUserAccountDialogComponent> = this.dialog.open(
+        ConfirmDeleteUserAccountDialogComponent,
+        { data: data, width: '550px', panelClass: 'error-modalbox' }
+      );
+
+      dialogRef.afterClosed().subscribe(result => {
+        if (result) {
+          const emitValue = (type === 'users')
+            ? { action, type, id: item.name, value: { user: value, group: item.group } }
+            : { action, type, id: item.name, value: item.group };
+          this.manageRolesGroups(emitValue);
+        }
+      });
+    } else if (action === 'update') {
+      this.manageRolesGroups({
+        action, type, value: {
+          name: item.group,
+          roleIds: this.extractIds(this.roles, item.selected_roles),
+          users: item.users || []
+        }
+      });
+    }
+    this.getEnvironmentHealthStatus();
+    this.resetDialog();
+  }
+
+  public manageRolesGroups($event) {
+    switch ($event.action) {
+      case 'create':
+        this.rolesService.setupNewGroup($event.value).subscribe(res => {
+          this.toastr.success('Group creation success!', 'Created!');
+          this.getGroupsData();
+        }, () => this.toastr.error('Group creation failed!', 'Oops!'));
+        break;
+      case 'update':
+        this.rolesService.updateGroup($event.value).subscribe(res => {
+          this.toastr.success('Group data successfully updated!', 'Success!');
+          this.getGroupsData();
+        }, () => this.toastr.error('Failed group data updating!', 'Oops!'));
+        break;
+      case 'delete':
+        if ($event.type === 'users') {
+          this.rolesService.removeUsersForGroup($event.value).subscribe(res => {
+            this.toastr.success('Users was successfully deleted!', 'Success!');
+            this.getGroupsData();
+          }, () => this.toastr.error('Failed users deleting!', 'Oops!'));
+        } else if ($event.type === 'group') {
+          console.log('delete group');
+          this.rolesService.removeGroupById($event.value).subscribe(res => {
+            this.toastr.success('Group was successfully deleted!', 'Success!');
+            this.getGroupsData();
+          }, () => this.toastr.error('Failed group deleting!', 'Oops!'));
+        }
+        break;
+      default:
+    }
+  }
+
+  public extractIds(sourceList, target) {
+    return sourceList.reduce((acc, item) => {
+      target.includes(item.description) && acc.push(item._id);
+      return acc;
+    }, []);
+  }
+
+  public updateGroupData(groups) {
+    this.groupsData = groups;
+
+    this.groupsData.forEach(item => {
+      item.selected_roles = item.roles.map(role => role.description);
+    });
+  }
+
+  public groupValidarion(): ValidatorFn {
+    const duplicateList: any = this.groupsData.map(item => item.group);
+    return <ValidatorFn>((control: FormControl) => {
+      if (control.value && duplicateList.includes(CheckUtils.delimitersFiltering(control.value))) {
+        return { duplicate: true };
+      }
+
+      if (control.value && !this.groupnamePattern.test(control.value))
+        return { patterns: true };
+
+      return null;
+    });
+  }
+
+  public compareObjects(o1: any, o2: any): boolean {
+    return o1.toLowerCase() === o2.toLowerCase();
+  }
+
+  public resetDialog() {
+    this.stepperView = false;
+    this.setupGroup = '';
+    this.setupUser = '';
+    this.manageUser = '';
+    this.setupRoles = [];
+    this.updatedRoles = [];
+  }
+
+  public removeUser(list, item): void {
+    list.splice(list.indexOf(item), 1);
+  }
+
+  public addUser(value: string, item): void {
+    if (value && value.trim()) {
+      item.users instanceof Array ? item.users.push(value.trim()) : item.users = [value.trim()];
+    }
+  }
+
+  private getEnvironmentHealthStatus() {
+    this.healthStatusService.getEnvironmentHealthStatus()
+      .subscribe((result: any) => this.healthStatus = result);
+  }
+}
+
+
+@Component({
+  selector: 'dialog-result-example-dialog',
+  template: `
+  <div class="dialog-header">
+    <h4 class="modal-title"><i class="material-icons">priority_high</i>Warning</h4>
+    <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+  </div>
+  <div mat-dialog-content class="content">
+    <p *ngIf="data.user">User <strong>{{ data.user }}</strong> will be deleted from <strong>{{ data.group }}</strong> group.</p>
+    <p *ngIf="data.id">Group <strong class="ellipsis group-name">{{ data.group }}</strong> will be decommissioned.</p>
+    <p class="m-top-20"><strong>Do you want to proceed?</strong></p>
+  </div>
+  <div class="text-center">
+    <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>
+  `,
+  styles: [`.group-name { max-width: 96%; display: inline-block; }`]
+})
+export class ConfirmDeleteUserAccountDialogComponent {
+  constructor(
+    public dialogRef: MatDialogRef<ConfirmDeleteUserAccountDialogComponent>,
+    @Inject(MAT_DIALOG_DATA) public data: any
+  ) { }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/app.component.html b/services/self-service/src/main/resources/webapp/src/app/app.component.html
index de9deb4..aa0751b 100644
--- a/services/self-service/src/main/resources/webapp/src/app/app.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/app.component.html
@@ -17,5 +17,4 @@
   ~ under the License.
   -->
 
-<dlab-navbar></dlab-navbar>
 <router-outlet></router-outlet>
diff --git a/services/self-service/src/main/resources/webapp/src/app/app.module.ts b/services/self-service/src/main/resources/webapp/src/app/app.module.ts
index 88aa630..0caf8eb 100644
--- a/services/self-service/src/main/resources/webapp/src/app/app.module.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/app.module.ts
@@ -19,31 +19,32 @@
 
 import { NgModule } from '@angular/core';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
-import { RouterModule, Router } from '@angular/router';
+import { RouterModule } from '@angular/router';
 import { BrowserModule } from '@angular/platform-browser';
 import { LocationStrategy, HashLocationStrategy } from '@angular/common';
 import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
 import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { ToastrModule } from 'ngx-toastr';
+
+import { HttpTokenInterceptor } from './core/interceptors/http.token.interceptor';
+import { NoCacheInterceptor } from './core/interceptors/nocache.interceptor';
+import { ErrorInterceptor } from './core/interceptors/error.interceptor';
 
 import { AppComponent } from './app.component';
 import { AppRoutingModule } from './app.routing.module';
 
 import { LoginModule } from './login/login.module';
-import { NavbarModule } from './shared/navbar';
+import { LayoutModule } from './layout/layout.module'
+
 import { GuidesModule } from './help';
 import { NotFoundModule } from './not-found/not-found.module';
 import { AccessDeniedModule } from './access-denied/access-denied.module';
 import { ResourcesModule } from './resources/resources.module';
-import { HttpTokenInterceptor } from './core/interceptors/http.token.interceptor';
-import { NoCacheInterceptor } from './core/interceptors/nocache.interceptor';
-import { ErrorInterceptor } from './core/interceptors/error.interceptor';
 
 import { ReportingModule } from './reporting/reporting.module';
-import { ManagenementModule } from './management';
+import { AdministrationModule } from './administration/administration.module';
 import { WebterminalModule } from './webterminal';
-
 import { CoreModule } from './core/core.module';
-import { ToastrModule } from 'ngx-toastr';
 
 @NgModule({
   declarations: [AppComponent],
@@ -54,20 +55,18 @@
     ReactiveFormsModule,
     HttpClientModule,
     LoginModule,
-    NavbarModule,
+    LayoutModule,
     ResourcesModule,
     GuidesModule,
     NotFoundModule,
     AccessDeniedModule,
     ReportingModule,
-    ManagenementModule,
+    AdministrationModule,
     WebterminalModule,
     RouterModule,
     AppRoutingModule,
     CoreModule.forRoot(),
-    ToastrModule.forRoot({
-      timeOut: 10000
-    })
+    ToastrModule.forRoot({ timeOut: 10000 })
   ],
   providers: [{
       provide: LocationStrategy,
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 eba8d7e..5135e02 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
@@ -21,50 +21,69 @@
 import { Routes, RouterModule } from '@angular/router';
 
 import { LoginComponent } from './login/login.module';
+import { LayoutComponent } from './layout/layout.component'
 import { ResourcesComponent } from './resources/resources.component';
 import { AccessNotebookGuideComponent, PublicKeyGuideComponent } from './help';
 import { NotFoundComponent } from './not-found/not-found.component';
 import { AccessDeniedComponent } from './access-denied/access-denied.component';
 import { ReportingComponent } from './reporting/reporting.component';
 import { WebterminalComponent } from './webterminal/webterminal.component';
-import { ManagementComponent } from './management/management.component';
-import { AuthorizationGuard, CheckParamsGuard, CloudProviderGuard } from './core/services';
+import { ManagementComponent } from './administration/management/management.component';
+import { ProjectComponent } from './administration/project/project.component';
+import { RolesComponent } from './administration/roles/roles.component';
+
+import { AuthorizationGuard, CheckParamsGuard, CloudProviderGuard, AdminGuard } from './core/services';
 
 const routes: Routes = [{
     path: 'login',
     component: LoginComponent
   }, {
-    path: 'resources_list',
-    component: ResourcesComponent,
-    canActivate: [CheckParamsGuard]
-  }, {
-    path: 'billing_report',
-    component: ReportingComponent,
-    canActivate: [AuthorizationGuard, CloudProviderGuard]
-  }, {
-    path: 'environment_management',
-    component: ManagementComponent,
-    canActivate: [AuthorizationGuard]
-  }, {
-    path: 'terminal/:id',
-    component: WebterminalComponent
-  }, {
-    path: 'help/publickeyguide',
-    component: PublicKeyGuideComponent,
-    canActivate: [AuthorizationGuard]
-  }, {
-    path: 'help/accessnotebookguide',
-    component: AccessNotebookGuideComponent,
-    canActivate: [AuthorizationGuard]
+    path: '',
+    canActivate: [AuthorizationGuard],
+    component: LayoutComponent,
+    children: [
+      {
+      path: '',
+      redirectTo: 'resources_list',
+      pathMatch: 'full'
+    }, {
+      path: 'resources_list',
+      component: ResourcesComponent,
+      canActivate: [CheckParamsGuard]
+    }, {
+      path: 'billing_report',
+      component: ReportingComponent,
+      canActivate: [AuthorizationGuard, CloudProviderGuard]
+    }, {
+      path: 'projects',
+      component: ProjectComponent,
+      canActivate: [AuthorizationGuard, AdminGuard],
+    }, {
+      path: 'roles',
+      component: RolesComponent,
+      canActivate: [AuthorizationGuard, AdminGuard],
+    }, {
+      path: 'environment_management',
+      component: ManagementComponent,
+      canActivate: [AuthorizationGuard, AdminGuard]
+    }, {
+      path: 'terminal/:id',
+      component: WebterminalComponent
+    }, {
+      path: 'help/publickeyguide',
+      component: PublicKeyGuideComponent,
+      canActivate: [AuthorizationGuard]
+    }, {
+      path: 'help/accessnotebookguide',
+      component: AccessNotebookGuideComponent,
+      canActivate: [AuthorizationGuard]
+    }
+  ]
   }, {
     path: '403',
     component: AccessDeniedComponent,
     canActivate: [AuthorizationGuard]
   }, {
-    path: '',
-    redirectTo: 'resources_list',
-    pathMatch: 'full'
-  }, {
     path: '**',
     component: NotFoundComponent
   }];
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 a8bf9c7..e182467 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
@@ -23,10 +23,10 @@
 import { AppRoutingService } from './services/appRouting.service';
 import { ApplicationSecurityService } from './services/applicationSecurity.service';
 import { HealthStatusService } from './services/healthStatus.service';
-import { UserAccessKeyService } from './services/userAccessKey.service';
 import { UserResourceService } from './services/userResource.service';
 import { AuthorizationGuard } from './services/authorization.guard';
 import { CloudProviderGuard } from './services/cloudProvider.guard';
+import { AdminGuard } from './services/admin.quard';
 import { CheckParamsGuard } from './services/checkParams.guard';
 import { LibrariesInstallationService } from './services/librariesInstallation.service';
 import { ManageUngitService } from './services/manageUngit.service';
@@ -37,6 +37,10 @@
 import { RolesGroupsService } from './services/rolesManagement.service';
 import { DataengineConfigurationService } from './services/dataengineConfiguration.service';
 import { StorageService } from './services/storage.service';
+import { ProjectService } from './services/project.service';
+import { EndpointService } from './services/endpoint.service';
+
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
 
 @NgModule({
   imports: [CommonModule],
@@ -53,9 +57,9 @@
       providers: [
         ApplicationSecurityService,
         AuthorizationGuard,
+        AdminGuard,
         CloudProviderGuard,
         CheckParamsGuard,
-        UserAccessKeyService,
         AppRoutingService,
         UserResourceService,
         HealthStatusService,
@@ -68,7 +72,12 @@
         RolesGroupsService,
         ApplicationServiceFacade,
         DataengineConfigurationService,
-        StorageService
+        StorageService,
+        ProjectService,
+        EndpointService,
+
+        { provide: MatDialogRef, useValue: {} },
+        { provide: MAT_DIALOG_DATA, useValue: [] }
       ]
     };
   }
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.scss b/services/self-service/src/main/resources/webapp/src/app/core/services/admin.quard.ts
similarity index 63%
copy from services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.scss
copy to services/self-service/src/main/resources/webapp/src/app/core/services/admin.quard.ts
index 6198578..a58e4cc 100644
--- a/services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/admin.quard.ts
@@ -1,4 +1,4 @@
-/*!
+/*
  * 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
@@ -17,24 +17,15 @@
  * under the License.
  */
 
-.dashboard_table {
-  .th_user,
-  .th_name {
-    width: 20%;
+import { Injectable } from '@angular/core';
+import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
+import { HealthStatusService } from './healthStatus.service';
+
+@Injectable()
+export class AdminGuard implements CanActivate {
+  constructor(private _healthStatus: HealthStatusService) {}
+
+  canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
+    return this._healthStatus.isPassageway('administration');
   }
-  .th_shape,
-  .th_status {
-    width: 12% !important;
-  }
-  .th_resources {
-    width: 33%;
-  }
-  .dashboard_table_body {
-    td:first-child {
-      cursor: default;
-    }
-  }
-}
-.source .resource-wrap .resource-name .detailed-link {
-  cursor: default !important;
 }
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 79ae239..2cfb52d 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
@@ -18,9 +18,8 @@
  */
 
 import { Injectable } from '@angular/core';
-import { Http, Response, RequestOptions, RequestMethod, Headers } from '@angular/http';
+import { RequestMethod } from '@angular/http';
 import { Observable } from 'rxjs';
-
 import { HttpClient } from '@angular/common/http';
 
 import { Dictionary } from '../collections';
@@ -41,7 +40,7 @@
   private static readonly EXPLORATORY_ENVIRONMENT = 'exploratory_environment';
   private static readonly IMAGE = 'image';
   private static readonly SCHEDULER = 'scheduler';
-  private static readonly EXPLORATORY_ENVIRONMENT_TEMPLATES = 'exploratory_templates';
+  private static readonly TEMPLATES = 'templates';
   private static readonly COMPUTATIONAL_RESOURCES_TEMLATES = 'computational_templates';
   private static readonly COMPUTATIONAL_RESOURCES = 'computational_resources';
   private static readonly COMPUTATIONAL_RESOURCES_DATAENGINE = 'computational_resources_dataengine';
@@ -68,6 +67,9 @@
   private static readonly BILLING = 'billing';
   private static readonly DOWNLOAD_REPORT = 'download_report';
   private static readonly SETTINGS = 'settings';
+  private static readonly PROJECT = 'project';
+  private static readonly USER_PROJECT = 'project/me';
+  private static readonly ENDPOINT = 'endpoint';
   private accessTokenKey: string = 'access_token';
   private requestRegistry: Dictionary<string>;
 
@@ -79,8 +81,7 @@
     return this.buildRequest(RequestMethod.Post,
       this.requestRegistry.Item(ApplicationServiceFacade.LOGIN),
       body,
-      { responseType: 'text', observe: 'response' }
-      );
+      { responseType: 'text', observe: 'response' });
   }
 
   public buildLogoutRequest(): Observable<any> {
@@ -94,8 +95,9 @@
     return this.buildRequest(RequestMethod.Post,
       this.requestRegistry.Item(ApplicationServiceFacade.AUTHORIZE),
       body,
-      { responseType: 'text',
-        headers: { 'Content-Type': 'text/plain'},
+      {
+        responseType: 'text',
+        headers: { 'Content-Type': 'text/plain' },
         observe: 'response'
       });
   }
@@ -111,7 +113,7 @@
     return this.buildRequest(RequestMethod.Get,
       this.requestRegistry.Item(ApplicationServiceFacade.ACCESS_KEY),
       null,
-      { observe: 'response'});
+      { observe: 'response' });
   }
 
   public buildGenerateAccessKey(): Observable<any> {
@@ -132,8 +134,9 @@
     return this.buildRequest(RequestMethod.Post,
       this.requestRegistry.Item(ApplicationServiceFacade.ACCESS_KEY),
       body,
-      { observe: 'response',
-        headers: { 'Upload': 'true'}
+      {
+        observe: 'response',
+        headers: { 'Upload': 'true' }
       });
   }
 
@@ -141,8 +144,9 @@
     return this.buildRequest(RequestMethod.Post,
       this.requestRegistry.Item(ApplicationServiceFacade.ACCESS_KEY) + option,
       body,
-      { observe: 'response',
-        headers: { 'Upload': 'true'}
+      {
+        observe: 'response',
+        headers: { 'Upload': 'true' }
       });
   }
 
@@ -152,15 +156,9 @@
       null);
   }
 
-  public buildGetExploratoryEnvironmentTemplatesRequest(): Observable<any> {
+  public buildGetTemplatesRequest(params): Observable<any> {
     return this.buildRequest(RequestMethod.Get,
-      this.requestRegistry.Item(ApplicationServiceFacade.EXPLORATORY_ENVIRONMENT_TEMPLATES),
-      null);
-  }
-
-  public buildGetComputationalResourcesTemplatesRequest(): Observable<any> {
-    return this.buildRequest(RequestMethod.Get,
-      this.requestRegistry.Item(ApplicationServiceFacade.COMPUTATIONAL_RESOURCES_TEMLATES),
+      this.requestRegistry.Item(ApplicationServiceFacade.TEMPLATES) + params,
       null);
   }
 
@@ -188,14 +186,14 @@
     return this.buildRequest(RequestMethod.Put,
       this.requestRegistry.Item(ApplicationServiceFacade.COMPUTATIONAL_RESOURCES_DATAENGINESERVICE),
       data,
-      { observe: 'response'});
+      { observe: 'response' });
   }
 
   public buildCreateComputationalResources_DataengineRequest(data): Observable<any> {
     return this.buildRequest(RequestMethod.Put,
       this.requestRegistry.Item(ApplicationServiceFacade.COMPUTATIONAL_RESOURCES_DATAENGINE),
       data,
-      { observe: 'response'});
+      { observe: 'response' });
   }
 
   public buildDeleteComputationalResourcesRequest(data): Observable<any> {
@@ -241,21 +239,21 @@
       data);
   }
 
-  public buildRunEdgeNodeRequest(): Observable<any>  {
+  public buildRunEdgeNodeRequest(): Observable<any> {
     return this.buildRequest(RequestMethod.Post,
       this.requestRegistry.Item(ApplicationServiceFacade.EDGE_NODE_START),
       null,
       { responseType: 'text' });
   }
 
-  public buildSuspendEdgeNodeRequest(): Observable<any>  {
+  public buildSuspendEdgeNodeRequest(): Observable<any> {
     return this.buildRequest(RequestMethod.Post,
       this.requestRegistry.Item(ApplicationServiceFacade.EDGE_NODE_STOP),
       null,
       { responseType: 'text', observe: 'response' });
   }
 
-  public buildRecreateEdgeNodeRequest(): Observable<any>  {
+  public buildRecreateEdgeNodeRequest(): Observable<any> {
     return this.buildRequest(RequestMethod.Post,
       this.requestRegistry.Item(ApplicationServiceFacade.EDGE_NODE_RECREATE),
       null,
@@ -284,7 +282,7 @@
     return this.buildRequest(RequestMethod.Post,
       this.requestRegistry.Item(ApplicationServiceFacade.LIB_INSTALL),
       data,
-      { observe: 'response', responseType: 'text'});
+      { observe: 'response', responseType: 'text' });
   }
 
   public buildGetInstalledLibrariesList(data): Observable<any> {
@@ -365,7 +363,7 @@
     return this.buildRequest(RequestMethod.Post,
       this.requestRegistry.Item(ApplicationServiceFacade.SCHEDULER) + param,
       data,
-      { observe: 'response'});
+      { observe: 'response' });
   }
 
   public buildResetScheduleSettings(data): Observable<any> {
@@ -384,29 +382,31 @@
     return this.buildRequest(RequestMethod.Get,
       this.requestRegistry.Item(ApplicationServiceFacade.ACTIVE_LIST),
       null);
-    }
+  }
 
   public buildManageEnvironment(action, data): Observable<any> {
     return this.buildRequest(RequestMethod.Post,
       this.requestRegistry.Item(ApplicationServiceFacade.ENV) + action,
       data,
-      { observe: 'response',
-        headers: { 'Content-Type': 'text/plain'}
+      {
+        observe: 'response',
+        headers: { 'Content-Type': 'text/plain' }
       });
-    }
+  }
 
   public buildGetAllEnvironmentData(): Observable<any> {
     return this.buildRequest(RequestMethod.Get,
       this.requestRegistry.Item(ApplicationServiceFacade.FULL_ACTIVE_LIST),
       null);
-    }
+  }
 
   public buildEnvironmentManagement(param, data): Observable<any> {
     return this.buildRequest(RequestMethod.Post,
       this.requestRegistry.Item(ApplicationServiceFacade.ENV) + param,
       data,
-      { observe: 'response',
-        headers: { 'Content-Type': 'text/plain'}
+      {
+        observe: 'response',
+        headers: { 'Content-Type': 'text/plain' }
       });
   }
 
@@ -414,7 +414,7 @@
     return this.buildRequest(RequestMethod.Put,
       this.requestRegistry.Item(ApplicationServiceFacade.BUDGET),
       data,
-      { observe: 'response'});
+      { observe: 'response' });
   }
 
   public buildGetSsnMonitorData(): Observable<any> {
@@ -434,7 +434,7 @@
     return this.buildRequest(method,
       this.requestRegistry.Item(ApplicationServiceFacade.SETTINGS) + param,
       null,
-      { observe: 'response'});
+      { observe: 'response' });
   }
 
   public buildGetGroupsData(): Observable<any> {
@@ -452,43 +452,37 @@
   public buildSetupNewGroup(data): Observable<any> {
     return this.buildRequest(RequestMethod.Post,
       this.requestRegistry.Item(ApplicationServiceFacade.GROUPS),
-      data,
-      this.getRequestOptions(false, true));
+      data);
   }
 
   public buildUpdateGroupData(data): Observable<any> {
     return this.buildRequest(RequestMethod.Put,
       this.requestRegistry.Item(ApplicationServiceFacade.GROUPS),
-      data,
-      this.getRequestOptions(false, true));
+      data);
   }
 
   public buildSetupRolesForGroup(data): Observable<any> {
     return this.buildRequest(RequestMethod.Put,
       this.requestRegistry.Item(ApplicationServiceFacade.GROUP_ROLE),
-      data,
-      this.getRequestOptions(false, true));
+      data);
   }
 
   public buildSetupUsersForGroup(data): Observable<any> {
     return this.buildRequest(RequestMethod.Put,
       this.requestRegistry.Item(ApplicationServiceFacade.GROUP_USER),
-      data,
-      this.getRequestOptions(false, true));
+      data);
   }
 
   public buildRemoveUsersForGroup(data): Observable<any> {
     return this.buildRequest(RequestMethod.Delete,
       this.requestRegistry.Item(ApplicationServiceFacade.GROUP_USER),
-      data,
-      this.getRequestOptions(false, true));
+      data);
   }
 
   public buildRemoveGroupById(data): Observable<any> {
     return this.buildRequest(RequestMethod.Delete,
       this.requestRegistry.Item(ApplicationServiceFacade.GROUPS),
-      data,
-      this.getRequestOptions(false, true));
+      data);
   }
 
   public buildGetClusterConfiguration(param): Observable<any> {
@@ -521,6 +515,60 @@
       null);
   }
 
+  public buildCreateProject(data): Observable<any> {
+    return this.buildRequest(RequestMethod.Post,
+      this.requestRegistry.Item(ApplicationServiceFacade.PROJECT),
+      data);
+  }
+
+  public buildUpdateProject(data): Observable<any> {
+    return this.buildRequest(RequestMethod.Put,
+      this.requestRegistry.Item(ApplicationServiceFacade.PROJECT),
+      data);
+  }
+
+  public buildGetProjectsList(): Observable<any> {
+    return this.buildRequest(RequestMethod.Get,
+      this.requestRegistry.Item(ApplicationServiceFacade.PROJECT),
+      null);
+  }
+
+  public buildGetUserProjectsList(): Observable<any> {
+    return this.buildRequest(RequestMethod.Get,
+      this.requestRegistry.Item(ApplicationServiceFacade.USER_PROJECT),
+      null);
+  }
+
+  public buildDeleteProject(param): Observable<any> {
+    return this.buildRequest(RequestMethod.Delete,
+      this.requestRegistry.Item(ApplicationServiceFacade.PROJECT) + param,
+      null);
+  }
+
+  public buildToggleProjectStatus(param, data): Observable<any> {
+    return this.buildRequest(RequestMethod.Post,
+      this.requestRegistry.Item(ApplicationServiceFacade.PROJECT) + param,
+      data);
+  }
+
+  public buildGetEndpointsData(): Observable<any> {
+    return this.buildRequest(RequestMethod.Get,
+      this.requestRegistry.Item(ApplicationServiceFacade.ENDPOINT),
+      null);
+  }
+
+  public buildCreateEndpoint(data): Observable<any> {
+    return this.buildRequest(RequestMethod.Post,
+      this.requestRegistry.Item(ApplicationServiceFacade.ENDPOINT),
+      data);
+  }
+
+  public buildDeleteEndpoint(param): Observable<any> {
+    return this.buildRequest(RequestMethod.Delete,
+      this.requestRegistry.Item(ApplicationServiceFacade.ENDPOINT) + param,
+      null);
+  }
+
   private setupRegistry(): void {
     this.requestRegistry = new Dictionary<string>();
 
@@ -541,8 +589,8 @@
       '/api/infrastructure/info');
     this.requestRegistry.Add(ApplicationServiceFacade.EXPLORATORY_ENVIRONMENT,
       '/api/infrastructure_provision/exploratory_environment');
-    this.requestRegistry.Add(ApplicationServiceFacade.EXPLORATORY_ENVIRONMENT_TEMPLATES,
-      '/api/infrastructure_templates/exploratory_templates');
+    this.requestRegistry.Add(ApplicationServiceFacade.TEMPLATES,
+      '/api/infrastructure_templates');
     this.requestRegistry.Add(ApplicationServiceFacade.IMAGE,
       '/api/infrastructure_provision/exploratory_environment/image');
     this.requestRegistry.Add(ApplicationServiceFacade.SCHEDULER,
@@ -593,6 +641,11 @@
     // billing report
     this.requestRegistry.Add(ApplicationServiceFacade.BILLING, '/api/billing/report');
     this.requestRegistry.Add(ApplicationServiceFacade.DOWNLOAD_REPORT, '/api/billing/report/download');
+
+    // project
+    this.requestRegistry.Add(ApplicationServiceFacade.PROJECT, '/api/project');
+    this.requestRegistry.Add(ApplicationServiceFacade.ENDPOINT, '/api/endpoint');
+    this.requestRegistry.Add(ApplicationServiceFacade.USER_PROJECT, '/api/project/me');
   }
 
   private buildRequest(method: RequestMethod, url: string, body: any, opt?) {
@@ -604,14 +657,4 @@
       return this.http.put(url, body, opt);
     } else return this.http.get(body ? (url + body) : url, opt);
   }
-
-  private getRequestOptions(json: boolean, auth: boolean) {
-    // const headers = new Headers();
-    // if (json)
-    //   headers.append('Content-type', 'application/json; charset=utf-8');
-    // if (auth)
-    //   headers.append('Authorization', 'Bearer ' + localStorage.getItem(this.accessTokenKey));
-    // const reqOpt = new RequestOptions({ headers: headers });
-    // return reqOpt;
-  }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/cloudProvider.guard.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/cloudProvider.guard.ts
index 5ebfa1e..7127cc0 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/cloudProvider.guard.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/cloudProvider.guard.ts
@@ -26,6 +26,6 @@
   constructor(private _healthStatus: HealthStatusService) {}
 
   canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot) {
-    return this._healthStatus.isBillingEnabled();
+    return this._healthStatus.isPassageway('billing');
   }
 }
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
new file mode 100644
index 0000000..98801b4
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/endpoint.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 { Observable } from 'rxjs';
+import { catchError, map } from 'rxjs/operators';
+
+import { ErrorUtils } from '../util';
+import { ApplicationServiceFacade } from './applicationServiceFacade.service';
+
+@Injectable()
+export class EndpointService {
+
+  constructor(
+    private applicationServiceFacade: ApplicationServiceFacade
+  ) { }
+
+  public getEndpointsData(): Observable<{}> {
+    return this.applicationServiceFacade
+      .buildGetEndpointsData()
+      .pipe(
+        map(response => response),
+        catchError(ErrorUtils.handleServiceError));
+  }
+
+  public createEndpoint(data): Observable<any> {
+    return this.applicationServiceFacade
+      .buildCreateEndpoint(data)
+      .pipe(
+        map(response => response),
+        catchError(ErrorUtils.handleServiceError));
+  }
+
+  public deleteEndpoint(data): Observable<any> {
+    const url = `/${data}`;
+    return this.applicationServiceFacade
+      .buildDeleteEndpoint(url)
+      .pipe(
+        map(response => response),
+        catchError(ErrorUtils.handleServiceError));
+  }
+}
+
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/healthStatus.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/healthStatus.service.ts
index 4908bc5..8dbad93 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/healthStatus.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/healthStatus.service.ts
@@ -21,7 +21,7 @@
 import { Observable, BehaviorSubject } from 'rxjs';
 import { catchError, map } from 'rxjs/operators';
 
-import { GeneralEnvironmentStatus } from '../../management/management.model';
+import { GeneralEnvironmentStatus } from '../../administration/management/management.model';
 import { ApplicationServiceFacade } from './applicationServiceFacade.service';
 import { AppRoutingService } from './appRouting.service';
 import { HTTP_STATUS_CODES, ErrorUtils } from '../util';
@@ -108,17 +108,21 @@
         catchError(ErrorUtils.handleServiceError));
   }
 
-  public isBillingEnabled(): Observable<boolean> {
+  public isPassageway(parameter: string): Observable<boolean> {
     return this.applicationServiceFacade
       .buildGetEnvironmentHealthStatus()
       .pipe(
         map(response => {
           if (response.status === HTTP_STATUS_CODES.OK) {
             const data = response.body;
-            if (!data.billingEnabled) {
+            if (parameter === 'billing' && !data.billingEnabled) {
               this.appRoutingService.redirectToHomePage();
               return false;
             }
+            if (parameter === 'administration' && !data.admin) {
+              this.appRoutingService.redirectToNoAccessPage();
+              return false;
+            }
           }
           return true;
         }));
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 4937cdd..caf1904 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
@@ -24,6 +24,7 @@
 export * from './userAccessKey.service';
 export * from './userResource.service';
 export * from './authorization.guard';
+export * from './admin.quard';
 export * from './cloudProvider.guard';
 export * from './checkParams.guard';
 export * from './librariesInstallation.service';
@@ -35,3 +36,5 @@
 export * from './rolesManagement.service';
 export * from './dataengineConfiguration.service';
 export * from './storage.service';
+export * from './project.service';
+export * from './endpoint.service';
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/project.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/project.service.ts
new file mode 100644
index 0000000..3923533
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/project.service.ts
@@ -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.
+ */
+
+import { Injectable } from '@angular/core';
+import { Observable } from 'rxjs';
+import { map, catchError } from 'rxjs/operators';
+
+import { ApplicationServiceFacade } from './applicationServiceFacade.service';
+import { ErrorUtils } from '../util';
+
+@Injectable()
+export class ProjectService {
+  constructor(private applicationServiceFacade: ApplicationServiceFacade) { }
+
+  public createProject(data): Observable<{}> {
+    return this.applicationServiceFacade
+      .buildCreateProject(data)
+      .pipe(
+        map(response => response),
+        catchError(ErrorUtils.handleServiceError));
+  }
+
+  public updateProject(data): Observable<{}> {
+    return this.applicationServiceFacade
+      .buildUpdateProject(data)
+      .pipe(
+        map(response => response),
+        catchError(ErrorUtils.handleServiceError));
+  }
+
+  public getProjectsList(): Observable<{}> {
+    return this.applicationServiceFacade
+      .buildGetProjectsList()
+      .pipe(
+        map(response => response),
+        catchError(ErrorUtils.handleServiceError));
+  }
+
+  public getUserProjectsList(): Observable<{}> {
+    return this.applicationServiceFacade
+      .buildGetUserProjectsList()
+      .pipe(
+        map(response => response),
+        catchError(ErrorUtils.handleServiceError));
+  }
+
+  public deleteProject(data): Observable<{}> {
+    const url = `/${data}`;
+    return this.applicationServiceFacade
+      .buildDeleteProject(url)
+      .pipe(
+        map(response => response),
+        catchError(ErrorUtils.handleServiceError));
+  }
+
+  public toggleProjectStatus(data, action): Observable<{}> {
+    const url = `/${action}`;
+    return this.applicationServiceFacade
+      .buildToggleProjectStatus(url, data)
+      .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 468ae5a..b07c2f1 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
@@ -28,17 +28,19 @@
 export class UserResourceService {
   constructor(private applicationServiceFacade: ApplicationServiceFacade) { }
 
-  public getExploratoryEnvironmentTemplates(): Observable<any> {
+  public getExploratoryTemplates(project): Observable<any> {
+    const url = `/${ project }/exploratory_templates`;
     return this.applicationServiceFacade
-      .buildGetExploratoryEnvironmentTemplatesRequest()
+      .buildGetTemplatesRequest(url)
       .pipe(
         map(response => response),
         catchError(ErrorUtils.handleServiceError));
   }
 
-  public getComputationalResourcesTemplates(): Observable<any> {
+  public getComputationalTemplates(project): Observable<any> {
+    const url = `/${ project }/computational_templates`;
     return this.applicationServiceFacade
-      .buildGetComputationalResourcesTemplatesRequest()
+      .buildGetTemplatesRequest(url)
       .pipe(
         map(response => response),
         catchError(ErrorUtils.handleServiceError));
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 36f8a63..bad6764 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
@@ -17,6 +17,8 @@
  * under the License.
  */
 
+import { PATTERNS } from './patterns';
+
 export class CheckUtils {
   public static isJSON(str) {
     try {
@@ -35,4 +37,8 @@
     }
     return true;
   }
+
+  public static delimitersFiltering(resource): string {
+    return resource.replace(PATTERNS.delimitersRegex, '').toString().toLowerCase();
+  }
 }
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 6dccb52..35462c0 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
@@ -23,3 +23,4 @@
 export * from './dateUtils';
 export * from './fileUtils';
 export * from './checkUtils';
+export * from './patterns';
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/create-resource.model.ts b/services/self-service/src/main/resources/webapp/src/app/core/util/patterns.ts
similarity index 71%
copy from services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/create-resource.model.ts
copy to services/self-service/src/main/resources/webapp/src/app/core/util/patterns.ts
index 9209b09..c99ac09 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/create-resource.model.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/util/patterns.ts
@@ -5,7 +5,7 @@
  * 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
+ * with the License.  You may obtain a copy  of the License at
  *
  *   http://www.apache.org/licenses/LICENSE-2.0
  *
@@ -17,9 +17,10 @@
  * under the License.
  */
 
-export class CreateResourceModel {
-  constructor(
-    public name: string,
-    public count: string
-  ) { }
+export const PATTERNS = {
+  namePattern: '[-_a-zA-Z0-9]*[_-]*[a-zA-Z0-9]+',
+  delimitersRegex: '/[-_]?/g',
+  url: '[-_a-zA-Z0-9/:.#!*();:@&=+$,/?#[]]*[_-]*[a-zA-Z0-9]+',
+  nodeCountPattern: '^[1-9]\\d*$',
+  integerRegex: '^[0-9]*$'
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/layout/layout.component.html b/services/self-service/src/main/resources/webapp/src/app/layout/layout.component.html
new file mode 100644
index 0000000..dcab0d8
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/layout/layout.component.html
@@ -0,0 +1,20 @@
+<!--
+  ~ 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.
+  -->
+
+<dlab-navbar></dlab-navbar>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/create-resource.model.ts b/services/self-service/src/main/resources/webapp/src/app/layout/layout.component.ts
similarity index 77%
copy from services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/create-resource.model.ts
copy to services/self-service/src/main/resources/webapp/src/app/layout/layout.component.ts
index 9209b09..9699698 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/create-resource.model.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/layout/layout.component.ts
@@ -17,9 +17,13 @@
  * under the License.
  */
 
-export class CreateResourceModel {
-  constructor(
-    public name: string,
-    public count: string
-  ) { }
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'dlab-layout',
+  templateUrl: './layout.component.html',
+})
+export class LayoutComponent implements OnInit {
+  constructor() { }
+  ngOnInit() { }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/billing/cost-details-dialog/index.ts b/services/self-service/src/main/resources/webapp/src/app/layout/layout.module.ts
similarity index 67%
copy from services/self-service/src/main/resources/webapp/src/app/resources/billing/cost-details-dialog/index.ts
copy to services/self-service/src/main/resources/webapp/src/app/layout/layout.module.ts
index 859295e..1f18582 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/billing/cost-details-dialog/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/layout/layout.module.ts
@@ -18,17 +18,15 @@
  */
 
 import { NgModule } from '@angular/core';
+import { RouterModule } from '@angular/router';
 import { CommonModule } from '@angular/common';
 
-import { MaterialModule } from '../../../shared/material.module';
-import { CostDetailsDialogComponent } from './cost-details-dialog.component';
-import { ModalModule } from '../../../shared';
-
-export * from './cost-details-dialog.component';
+import { LayoutComponent } from './layout.component';
+import { NavbarModule } from '../shared/navbar';
 
 @NgModule({
-  imports: [CommonModule, ModalModule, MaterialModule],
-  declarations: [CostDetailsDialogComponent],
-  exports: [CostDetailsDialogComponent]
+  imports: [CommonModule, RouterModule, NavbarModule],
+  declarations: [LayoutComponent],
+  exports: [LayoutComponent]
 })
-export class CostDetailsDialogModule {}
+export class LayoutModule { }
\ No newline at end of file
diff --git a/services/self-service/src/main/resources/webapp/src/app/login/login.component.ts b/services/self-service/src/main/resources/webapp/src/app/login/login.component.ts
index b456bf1..489acae 100644
--- a/services/self-service/src/main/resources/webapp/src/app/login/login.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/login/login.component.ts
@@ -50,11 +50,11 @@
   }
 
   ngOnInit() {
-    this.applicationSecurityService.isLoggedIn().subscribe(result => {
-      console.log('LOGGED IN  /login component');
+    // this.applicationSecurityService.isLoggedIn().subscribe(result => {
+    //   console.log('LOGGED IN  /login component');
 
-      result && this.checkHealthStatusAndRedirect(result);
-    });
+    //   result && this.checkHealthStatusAndRedirect(result);
+    // });
   }
 
   ngOnDestroy() {
@@ -69,7 +69,7 @@
       .login(this.model)
       .subscribe((result) => {
         if (result) {
-          this.checkHealthStatusAndRedirect(result);
+          this.appRoutingService.redirectToHomePage();
           return true;
         }
 
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/backup-dilog/backup-dilog.component.ts b/services/self-service/src/main/resources/webapp/src/app/management/backup-dilog/backup-dilog.component.ts
deleted file mode 100644
index 7569a78..0000000
--- a/services/self-service/src/main/resources/webapp/src/app/management/backup-dilog/backup-dilog.component.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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, ViewChild, Output, EventEmitter } from '@angular/core';
-import { DICTIONARY } from '../../../dictionary/global.dictionary';
-
-import { BackupOptionsModel } from '../management.model';
-
-@Component({
-  selector: 'dlab-backup-dilog',
-  templateUrl: './backup-dilog.component.html',
-  styleUrls: ['./backup-dilog.component.scss']
-})
-export class BackupDilogComponent implements OnInit {
-  readonly DICTIONARY = DICTIONARY;
-  public backupOptions: BackupOptionsModel = new BackupOptionsModel([], [], [], [], false, false);
-  public valid: boolean = true;
-
-  @ViewChild('bindDialog') bindDialog;
-  @Output() backupOpts: EventEmitter<{}> = new EventEmitter();
-
-  ngOnInit() {
-    this.backupOptions.setDegault();
-    this.bindDialog.onClosing = () => this.backupOptions.setDegault();
-  }
-
-  public open(param): void {
-    this.valid = true;
-    this.bindDialog.open(param);
-  }
-
-  public onHoldChanged($event, key): void {
-    this.backupOptions[key] instanceof Array
-      ? (this.backupOptions[key][0] = $event.checked ? 'all' : 'skip')
-      : (this.backupOptions[key] = !this.backupOptions[key]);
-
-    this.checkValidity();
-  }
-
-  public applyOptions(): void {
-    this.backupOpts.emit(this.backupOptions);
-    this.backupOptions.setDegault();
-    this.bindDialog.close();
-  }
-
-  private checkValidity(): void {
-    const items = [];
-
-    Object.keys(this.backupOptions).forEach(el => {
-      if (this.backupOptions[el] instanceof Array) {
-        if (this.backupOptions[el][0] && this.backupOptions[el][0] !== 'skip') items.push(this.backupOptions[el][0]);
-      } else {
-        if (this.backupOptions[el]) items.push(this.backupOptions[el]) ;
-      }
-    });
-
-    this.valid = items.length > 0;
-  }
-}
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/index.ts b/services/self-service/src/main/resources/webapp/src/app/management/index.ts
deleted file mode 100644
index d49689c..0000000
--- a/services/self-service/src/main/resources/webapp/src/app/management/index.ts
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * 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 { FormsModule, ReactiveFormsModule } from '@angular/forms';
-
-import {
-  ModalModule,
-  UploadKeyDialogModule,
-  ProgressDialogModule,
-  BubbleModule,
-  ConfirmationDialogModule
-} from '../shared';
-import { MaterialModule } from '../shared/material.module';
-
-import { ManagementComponent } from './management.component';
-import {
-  ManagementGridComponent,
-  ConfirmationDialogComponent
-} from './management-grid/management-grid.component';
-import { ComputationalResourcesModule } from '../resources/computational/computational-resources-list';
-
-
-
-
-import { FormControlsModule } from '../shared/form-controls';
-import { BackupDilogComponent } from './backup-dilog/backup-dilog.component';
-import {
-  ManageEnvironmentComponent,
-  ConfirmActionDialogComponent
-} from './manage-environment/manage-environment-dilog.component';
-
-import { GroupNameValidationDirective } from './manage-roles-groups/group-name-validarion.directive';
-import { DirectivesModule } from '../core/directives';
-
-import { SsnMonitorComponent } from './ssn-monitor/ssn-monitor.component';
-import { ManageRolesGroupsComponent, ConfirmDeleteUserAccountDialogComponent } from './manage-roles-groups/manage-roles-groups.component';
-
-export * from './management.component';
-
-@NgModule({
-  imports: [
-    CommonModule,
-    FormsModule,
-    ReactiveFormsModule,
-    ModalModule,
-    UploadKeyDialogModule,
-    ProgressDialogModule,
-    BubbleModule,
-    ConfirmationDialogModule,
-    ComputationalResourcesModule,
-    FormControlsModule,
-    DirectivesModule,
-    MaterialModule
-  ],
-  declarations: [
-    ManagementComponent,
-    ManagementGridComponent,
-
-    GroupNameValidationDirective,
-    BackupDilogComponent,
-    ManageEnvironmentComponent,
-    ConfirmationDialogComponent,
-    ConfirmActionDialogComponent,
-    ConfirmDeleteUserAccountDialogComponent,
-    SsnMonitorComponent,
-    ManageRolesGroupsComponent
-  ],
-  entryComponents: [ConfirmationDialogComponent, ConfirmActionDialogComponent, ConfirmDeleteUserAccountDialogComponent],
-  exports: [ManagementComponent]
-})
-export class ManagenementModule {}
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/manage-roles-groups.component.html b/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/manage-roles-groups.component.html
deleted file mode 100644
index 85b751b..0000000
--- a/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/manage-roles-groups.component.html
+++ /dev/null
@@ -1,154 +0,0 @@
-<!--
-  ~ 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-dialog #bindDialog modalClass="manage-roles-dialog modal-xxl">
-  <modal-header>
-    <h4 class="modal-title">Manage roles</h4>
-  </modal-header>
-  <modal-content>
-    <div class="content-box">
-      <button mat-raised-button class="butt add-group" (click)="stepperView = !stepperView">
-        <i class="material-icons">people_outline</i>Add group
-      </button>
-      <mat-horizontal-stepper #stepper *ngIf="stepperView" class="stepper ani">
-        <mat-step>
-          <ng-template matStepLabel>Groups</ng-template>
-          <div class="inner-step mat-reset">
-            <input [validator]="groupValidarion()" type="text" placeholder="Enter group name" [(ngModel)]="setupGroup" #setupGroupName="ngModel">
-            <div class="danger_color" *ngIf="setupGroupName.errors?.patterns && setupGroupName.dirty">Group name can only contain letters, numbers, hyphens and '_'</div>
-            <div class="danger_color" *ngIf="setupGroupName.errors?.duplicate && setupGroupName.dirty">Group name already exists</div>
-          </div>
-          <div class="text-center m-bott-10">
-            <button mat-raised-button (click)="resetDialog()" class="butt">Cancel</button>
-            <button mat-raised-button matStepperNext class="butt">Next<i class="material-icons">keyboard_arrow_right</i></button>
-          </div>
-        </mat-step>
-        <mat-step>
-          <ng-template matStepLabel>Roles</ng-template>
-          <div class="inner-step mat-reset">
-            <div class="selector-wrapper">
-              <!-- <multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="'role'" [items]="rolesList" [model]="setupRoles"></multi-select-dropdown> -->
-              <mat-form-field>
-                  <mat-select multiple [compareWith]="compareObjects" name="roles" [(value)]="setupRoles" placeholder="Select roles">
-                    <mat-option class="multiple-select" disabled>
-                      <a class="select ani" (click)="selectAllOptions(setupRoles, rolesList)">
-                        <i class="material-icons">playlist_add_check</i>&nbsp;All
-                      </a>
-                      <a class="deselect ani" (click)="selectAllOptions(setupRoles)">
-                        <i class="material-icons">clear</i>&nbsp;None
-                      </a>
-                    </mat-option>
-                    <mat-option *ngFor="let role of rolesList" [value]="role">
-                      {{ role }}
-                    </mat-option>
-                  </mat-select>
-                  <button class="caret">
-                    <i class="material-icons">keyboard_arrow_down</i>
-                  </button>
-                </mat-form-field>
-            </div>
-          </div>
-          <div class="text-center m-bott-10">
-            <button mat-raised-button matStepperPrevious class="butt"><i class="material-icons">keyboard_arrow_left</i>Back</button>
-            <button mat-raised-button (click)="resetDialog()" class="butt">Cancel</button>
-            <button mat-raised-button matStepperNext class="butt">Next<i class="material-icons">keyboard_arrow_right</i></button>
-          </div>
-        </mat-step>
-        <mat-step>
-          <ng-template matStepLabel>Users</ng-template>
-          <div class="inner-step mat-reset">
-            <input type="text" placeholder="Enter user login" [(ngModel)]="setupUser">
-          </div>
-          <div class="text-center m-bott-10">
-            <button mat-raised-button matStepperPrevious class="butt"><i class="material-icons">keyboard_arrow_left</i>Back</button>
-            <button mat-raised-button (click)="resetDialog()" class="butt">Cancel</button>
-            <button mat-raised-button (click)="manageAction('create', 'group')" class="butt butt-success"
-                    [disabled]="!setupGroup || setupGroupName.errors?.pattern || !setupRoles.length > 0">Create</button>
-          </div>
-        </mat-step>
-      </mat-horizontal-stepper>
-      <mat-divider></mat-divider>
-      <div *ngIf="groupsData.length" class="ani">
-        <table class="dashboard_table">
-          <tr>
-            <th class="th_name groups">Name</th>
-            <th class="roles">Roles</th>
-            <th class="users">Users</th>
-            <th class="th_actions">Action</th>
-          </tr>
-          <tr *ngFor="let item of groupsData" class="dashboard_table_body filter-row">
-            <td>{{ item.group }}</td>
-            <td class="roles mat-reset">
-              <div class="selector-wrapper-edit">
-                <mat-form-field>
-                  <mat-select multiple [compareWith]="compareObjects" name="selected_roles" [(value)]="item.selected_roles" placeholder="Select roles">
-                    <mat-option class="multiple-select" disabled>
-                      <a class="select ani" (click)="selectAllOptions(item, rolesList, 'selected_roles')">
-                        <i class="material-icons">playlist_add_check</i>&nbsp;All
-                      </a>
-                      <a class="deselect ani" (click)="selectAllOptions(item, null, 'selected_roles')">
-                        <i class="material-icons">clear</i>&nbsp;None
-                      </a>
-                    </mat-option>
-                    <mat-option *ngFor="let role of rolesList" [value]="role">
-                      {{ role }}
-                    </mat-option>
-                  </mat-select>
-                  <button class="caret ani">
-                    <i class="material-icons">keyboard_arrow_down</i>
-                  </button>
-                </mat-form-field>
-              </div>
-            </td>
-            <td class="users-list ani">
-              <mat-form-field class="chip-list">
-                <input #user matInput placeholder="Enter user login" pattern="[@.-_0-9a-zA-Z]" (keydown.enter)="addUser(user.value, item); user.value = ''">
-                <button mat-icon-button matSuffix (click)="addUser(user.value, item); user.value = ''">
-                  <mat-icon>person_add</mat-icon>
-                </button>
-              </mat-form-field>
-              <div class="list-selected list-container ani">
-                <mat-chip-list>
-                  <mat-chip *ngFor="let user of item.users">
-                    {{ user }}
-                    <a class="material-icons" (click)="removeUser(item.users, user)">clear</a>
-                  </mat-chip>
-                </mat-chip-list>
-              </div>
-            </td>
-            <td class="actions">
-              <button mat-icon-button class="reset ani" (click)="manageAction('delete', 'group', item)">
-                <i class="material-icons">close</i>
-              </button>
-
-              <button mat-icon-button class="apply ani" matTooltip="Group cannot be updated without any selected role"
-                      matTooltipPosition="above"
-                      [matTooltipDisabled]="item.selected_roles.length > 0"
-                      [ngClass]="{ 'not-allowed' : !item.selected_roles.length }"
-                      (click)="manageAction('update', 'group', item)">
-                <i class="material-icons">done</i>
-              </button>
-            </td>
-          </tr>
-        </table>
-      </div>
-    </div>
-  </modal-content>
-</modal-dialog>
-
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/manage-roles-groups.component.ts b/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/manage-roles-groups.component.ts
deleted file mode 100644
index 932e42b..0000000
--- a/services/self-service/src/main/resources/webapp/src/app/management/manage-roles-groups/manage-roles-groups.component.ts
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * 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, ViewChild, Output, EventEmitter, Inject } from '@angular/core';
-import { ValidatorFn, FormControl, NgModel } from '@angular/forms';
-import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
-import { DICTIONARY } from '../../../dictionary/global.dictionary';
-
-@Component({
-  selector: 'dlab-manage-roles-groups',
-  templateUrl: './manage-roles-groups.component.html',
-  styleUrls: ['../../resources/resources-grid/resources-grid.component.css', './manage-roles-groups.component.scss']
-})
-export class ManageRolesGroupsComponent implements OnInit {
-  readonly DICTIONARY = DICTIONARY;
-
-  public groupsData: Array<any> = [];
-  public roles: Array<any> = [];
-  public rolesList: Array<string> = [];
-  public setupGroup: string = '';
-  public setupUser: string = '';
-  public manageUser: string = '';
-  public setupRoles: Array<string> = [];
-  public updatedRoles: Array<string> = [];
-  public delimitersRegex = /[-_]?/g;
-  public groupnamePattern = new RegExp(/^[a-zA-Z0-9_\-]+$/);
-
-  @ViewChild('bindDialog') bindDialog;
-  @Output() manageRolesGroupAction: EventEmitter<{}> = new EventEmitter();
-  stepperView: boolean = false;
-
-  constructor(public dialog: MatDialog) { }
-
-  ngOnInit() {
-    this.bindDialog.onClosing = () => this.resetDialog();
-  }
-
-  public open(param, groups, roles): void {
-    this.roles = roles;
-    this.rolesList = roles.map(role => role.description);
-    this.updateGroupData(groups);
-
-    this.stepperView = false;
-    this.bindDialog.open(param);
-  }
-
-  public onUpdate($event) {
-    if ($event.type === 'role') {
-      this.setupRoles = $event.model;
-    } else {
-      this.updatedRoles = $event.model;
-    }
-    $event.$event.preventDefault();
-  }
-
-  public selectAllOptions(item, values, byKey?) {
-    byKey ? (item[byKey] = values ? values : []) : this.setupRoles = values ? values : [];
-  }
-
-  public manageAction(action: string, type: string, item?: any, value?) {
-    if (action === 'create') {
-      this.manageRolesGroupAction.emit(
-        { action, type, value: {
-          name: this.setupGroup,
-          users: this.setupUser ? this.setupUser.split(',').map(elem => elem.trim()) : [],
-          roleIds: this.extractIds(this.roles, this.setupRoles)
-        }
-      });
-      this.stepperView = false;
-    } else if (action === 'delete') {
-      const data = (type === 'users') ? {group: item.group, user: value} : {group: item.group, id: item};
-      const dialogRef: MatDialogRef<ConfirmDeleteUserAccountDialogComponent> = this.dialog.open(
-        ConfirmDeleteUserAccountDialogComponent,
-        { data: data, width: '550px', panelClass: 'error-modalbox' }
-      );
-
-      dialogRef.afterClosed().subscribe(result => {
-        if (result) {
-          const emitValue = (type === 'users')
-            ? {action, type, id: item.name, value: { user: value, group: item.group }}
-            : {action, type, id: item.name, value: item.group} ;
-          this.manageRolesGroupAction.emit(emitValue);
-        }
-      });
-    } else if (action === 'update') {
-      this.manageRolesGroupAction.emit({action, type, value: {
-        name: item.group,
-        roleIds: this.extractIds(this.roles, item.selected_roles),
-        users: item.users || [] }});
-    }
-    this.resetDialog();
-  }
-
-  public extractIds(sourceList, target) {
-    return sourceList.reduce((acc, item) => {
-      target.includes(item.description) && acc.push(item._id);
-      return acc;
-    }, []);
-  }
-
-  public updateGroupData(groups) {
-    this.groupsData = groups;
-
-    this.groupsData.forEach(item => {
-      item.selected_roles = item.roles.map(role => role.description);
-    });
-  }
-
-  public groupValidarion(): ValidatorFn {
-
-    const duplicateList: any = this.groupsData.map(item => item.group);
-    return <ValidatorFn>((control: FormControl) => {
-      if (control.value && duplicateList.includes(this.delimitersFiltering(control.value)))
-        return { duplicate: true };
-
-      if (control.value && !this.groupnamePattern.test(control.value))
-        return { patterns: true };
-
-      return null;
-    });
-  }
-
-  public compareObjects(o1: any, o2: any): boolean {
-    return o1.toLowerCase() === o2.toLowerCase();
-  }
-
-  public delimitersFiltering(resource): string {
-    return resource.replace(this.delimitersRegex, '').toString().toLowerCase();
-  }
-
-  public resetDialog() {
-    this.stepperView = false;
-    this.setupGroup = '';
-    this.setupUser = '';
-    this.manageUser = '';
-    this.setupRoles = [];
-    this.updatedRoles = [];
-  }
-
-  public removeUser(list, item): void {
-    list.splice(list.indexOf(item), 1);
-  }
-
-  public addUser(value: string, item): void {
-    if (value && value.trim()) {
-      item.users instanceof Array ? item.users.push(value.trim()) : item.users = [value.trim()];
-    }
-  }
-}
-
-
-@Component({
-  selector: 'dialog-result-example-dialog',
-  template: `
-  <div class="dialog-header">
-    <h4 class="modal-title"><i class="material-icons">priority_high</i>Warning</h4>
-    <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
-  </div>
-  <div mat-dialog-content class="content">
-    <p *ngIf="data.user">User <strong>{{ data.user }}</strong> will be deleted from <strong>{{ data.group }}</strong> group.</p>
-    <p *ngIf="data.id">Group <strong>{{ data.group }}</strong> will be decommissioned.</p>
-    <p class="m-top-20"><strong>Do you want to proceed?</strong></p>
-  </div>
-  <div class="text-center">
-    <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>
-  `,
-  styles: []
-})
-export class ConfirmDeleteUserAccountDialogComponent {
-  constructor(
-    public dialogRef: MatDialogRef<ConfirmDeleteUserAccountDialogComponent>,
-    @Inject(MAT_DIALOG_DATA) public data: any
-  ) { }
-}
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.html b/services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.html
deleted file mode 100644
index 6b8bb95..0000000
--- a/services/self-service/src/main/resources/webapp/src/app/management/management-grid/management-grid.component.html
+++ /dev/null
@@ -1,161 +0,0 @@
-<!--
-  ~ 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 class="dashboard_table" *ngIf="isAdmin; else users">
-  <tr>
-    <th class="th_user">User</th>
-    <th class="th_name">Name</th>
-    <th class="th_status">Status</th>
-    <th class="th_shape">Shape / Resource id</th>
-    <th class="th_resources">Computational resources</th>
-    <th class="th_actions">Action</th>
-  </tr>
-
-  <tr *ngFor="let env of allEnvironmentData" class="dashboard_table_body">
-    <td>{{ env.user }}</td>
-    <td [ngClass]="{'capitalize': env.name === 'edge node'}">{{ env.name }}</td>
-    <td class="status" ngClass="{{env.status || ''}}">{{env.status}}</td>
-    <td>{{ env.shape || env.ip }}</td>
-    <td>
-      <div class="source" *ngIf="env.resources">
-        <div *ngIf="!env.resources?.length">
-          <span *ngIf="!env.resources.length" class="no-details">no details</span>
-        </div>
-        <div *ngIf="env.resources?.length">
-          <div *ngFor="let resource of env.resources" class="resource-wrap">
-            <div class="resource-name">
-              <a class="detailed-link">
-                {{ resource.computational_name }}
-              </a>
-            </div>
-            <span ngClass="{{resource.status || ''}}" class="resource-status">{{ resource.status }}</span>
-            <div class="resource-actions">
-              <a class="start-stop-action" *ngIf="resource.image === 'docker.dlab-dataengine'">
-                <i class="material-icons" (click)="toggleResourceAction(env, 'stop', resource)"
-                  [ngClass]="{'not-allowed' : resource.status !== 'running' || env.user.toLowerCase() === currentUser && healthStatus !== 'ok' }">pause_circle_outline</i>
-              </a>
-
-              <a class="remove_butt" (click)="toggleResourceAction(env, 'terminate', resource)"
-                  [ngClass]="{ 'disabled' : env.status !== 'running' || resource.status !== 'running'
-                              && resource.status !== 'stopped' || env.user.toLowerCase() === currentUser && healthStatus !== 'ok' }">
-                <i class="material-icons">highlight_off</i>
-              </a>
-            </div>
-          </div>
-        </div>
-      </div>
-    </td>
-    <td class="settings">
-      <span #settings class="actions" (click)="actions.toggle($event, settings)" [ngClass]="{ 'disabled'
-            : (!uploadKey && env.type === 'notebook' && env.user.toLowerCase() === currentUser)
-            || (env.status !== 'running' && env.status !== 'stopped' && env.status !== 'stopping' && env.status !== 'failed' )
-            || (env.type === 'edge node' && env.user.toLowerCase() === currentUser && env.status === 'stopping')
-            || env.type === 'edge node' && env.user.toLowerCase() !== currentUser && env.status !== 'running'
-            || env.user.toLowerCase() === currentUser && healthStatus !== 'ok' && env.type !== 'edge node' }"></span>
-      <bubble-up #actions class="list-menu" position="bottom-left" alternative="top-left">
-        <ul class="list-unstyled">
-          <li
-            matTooltip="{{ env.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" [matTooltipDisabled]="!isResourcesInProgress(env)"
-            [hidden]="env.name === 'edge node' && env.status === 'stopped'">
-            <div (click)="toggleResourceAction(env, 'stop')"
-              [ngClass]="{'not-allowed' : env.status === 'stopped' || env.status === 'stopping' || env.status === 'starting' || env.status === 'creating image' || env.status === 'failed' || isResourcesInProgress(env)}">
-              <i class="material-icons">pause_circle_outline</i>
-              <span>Stop</span>
-            </div>
-          </li>
-          <li *ngIf="env.name !== 'edge node'"
-            matTooltip="Unable to terminate notebook because at least one computational resource is in progress"
-            matTooltipPosition="above" [matTooltipDisabled]="!isResourcesInProgress(env)">
-            <div (click)="toggleResourceAction(env, 'terminate')"
-              [ngClass]="{'not-allowed' : env.status !== 'running' && env.status !== 'stopped' || isResourcesInProgress(env)}">
-              <i class="material-icons">phonelink_off</i>
-              <span>Terminate</span>
-            </div>
-          </li>
-
-          <div *ngIf="env.name === 'edge node' && env.user.toLowerCase() === currentUser">
-            <li (click)="toggleResourceAction(env, 'run')" *ngIf="env.status === 'stopped'">
-              <i class="material-icons">play_circle_outline</i>
-              <span>Start</span>
-            </li>
-            <li (click)="toggleResourceAction(env, 'recreate')" *ngIf="env.status === 'terminated'">
-              <i class="material-icons">refresh</i>
-              <span>Recreate</span>
-            </li>
-            <li *ngIf="!isResourcesInProgress(env)" (click)="showReuploaKeydDialog()">
-              <i class="material-icons">sync_problem</i>
-              <span>Reupload key</span>
-            </li>
-          </div>
-        </ul>
-      </bubble-up>
-    </td>
-  </tr>
-</table>
-
-<ng-template #users>
-  <table class="dashboard_table">
-    <tr>
-      <th class="th_name">Type</th>
-      <th>Resource id</th>
-      <th class="th_status">Status</th>
-      <th class="th_actions">Action</th>
-    </tr>
-    <tr *ngFor="let env of environmentsHealthStatuses" class="dashboard_table_body">
-      <td>{{env.type}}</td>
-      <td>{{env.resource_id}}</td>
-      <td class="status" ngClass="{{env.status || ''}}">{{env.status}}</td>
-      <td class="settings">
-        <span #settings (click)="actions.toggle($event, settings)" class="actions" [ngClass]="{'disabled': env.status !== 'running'
-              && env.status !== 'stopped'
-              && env.status !== 'terminated'
-              || notebookInProgress
-              || !uploadKey && env.status !== 'failed' }">
-        </span>
-
-        <bubble-up #actions class="list-menu" position="bottom-left" alternative="top-left">
-          <ul class="list-unstyled">
-            <li (click)="toggleResourceAction(env, 'stop')" *ngIf="env.status === 'running'">
-              <i class="material-icons">pause_circle_outline</i>
-              <span>Stop</span>
-            </li>
-            <li (click)="toggleResourceAction(env, 'run')" *ngIf="env.status === 'stopped'">
-              <i class="material-icons">play_circle_outline</i>
-              <span>Start</span>
-            </li>
-            <li (click)="toggleResourceAction(env, 'recreate')" *ngIf="env.status === 'terminated'">
-              <i class="material-icons">refresh</i>
-              <span>Recreate</span>
-            </li>
-            <li *ngIf="!anyEnvInProgress" (click)="showReuploaKeydDialog()">
-              <i class="material-icons">sync_problem</i>
-              <span>Reupload key</span>
-            </li>
-          </ul>
-        </bubble-up>
-      </td>
-    </tr>
-  </table>
-</ng-template>
-
-<confirmation-dialog #confirmationDialog [manageAction]="isAdmin" (buildGrid)="buildGrid()"></confirmation-dialog>
-<key-upload-dialog #keyReuploadDialog [primaryUploading]="false" (checkInfrastructureCreationProgress)="buildGrid()"
-  (generateUserKey)="generateUserKey()">
-</key-upload-dialog>
\ No newline at end of file
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/management.component.html b/services/self-service/src/main/resources/webapp/src/app/management/management.component.html
deleted file mode 100644
index b0b2788..0000000
--- a/services/self-service/src/main/resources/webapp/src/app/management/management.component.html
+++ /dev/null
@@ -1,55 +0,0 @@
-<!--
-  ~ 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="sub-nav base-retreat">
-    <div *ngIf="healthStatus?.admin" class="admin-group">
-        <button mat-raised-button class="butt ssn" (click)="openManageRolesDialog()">
-        <i class="material-icons"></i>Manage roles
-      </button>
-        <button mat-raised-button class="butt ssn" (click)="openSsnMonitorDialog()">
-        <i class="material-icons"></i>SSN Monitor
-      </button>
-        <button mat-raised-button class="butt env" (click)="openManageEnvironmentDialog()">
-        <i class="material-icons"></i>Manage environment
-      </button>
-        <button mat-raised-button class="butt" (click)="showBackupDialog()" [disabled]="creatingBackup">
-        <i class="material-icons">backup</i>Backup
-      </button>
-    </div>
-    <button mat-raised-button class="butt" (click)="buildGrid()">
-    <i class="material-icons">autorenew</i>Refresh
-  </button>
-</div>
-
-<management-grid [currentUser]="user.toLowerCase()" [uploadKey]="uploadKey" [healthStatus]="healthStatus?.status" [isAdmin]="healthStatus?.admin" [allEnvironmentData]="allEnvironmentData" [environmentsHealthStatuses]="healthStatus?.list_resources" (refreshGrid)="buildGrid()"
-    (actionToggle)="manageEnvironmentAction($event)">
-</management-grid>
-
-
-<dlab-backup-dilog #backupDialog (backupOpts)="createBackup($event)">
-</dlab-backup-dilog>
-
-<dlab-manage-env-dilog #manageEnvDialog (manageEnv)="manageEnvironment($event)" (setBudget)="setBudgetLimits($event)">
-</dlab-manage-env-dilog>
-
-<progress-dialog #preloaderModal></progress-dialog>
-<dlab-ssn-monitor #ssnMonitor></dlab-ssn-monitor>
-
-<dlab-manage-roles-groups #rolesGroupsModal (manageRolesGroupAction)="manageRolesGroups($event)">
-</dlab-manage-roles-groups>
\ No newline at end of file
diff --git a/services/self-service/src/main/resources/webapp/src/app/management/management.component.ts b/services/self-service/src/main/resources/webapp/src/app/management/management.component.ts
deleted file mode 100644
index b55d5da..0000000
--- a/services/self-service/src/main/resources/webapp/src/app/management/management.component.ts
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * 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, ViewChild, OnDestroy } from '@angular/core';
-import { ToastrService } from 'ngx-toastr';
-import { Subscription } from 'rxjs';
-
-import {
-  HealthStatusService,
-  ManageEnvironmentsService,
-  UserAccessKeyService,
-  BackupService,
-  UserResourceService,
-  RolesGroupsService,
-  StorageService
-} from '../core/services';
-
-import { EnvironmentModel, GeneralEnvironmentStatus } from './management.model';
-import { HTTP_STATUS_CODES } from '../core/util';
-
-@Component({
-  selector: 'environments-management',
-  templateUrl: './management.component.html',
-  styleUrls: ['./management.component.scss']
-})
-export class ManagementComponent implements OnInit, OnDestroy {
-  public user: string = '';
-  public healthStatus: GeneralEnvironmentStatus;
-  public allEnvironmentData: Array<EnvironmentModel>;
-  public uploadKey: boolean = true;
-  public anyEnvInProgress: boolean = false;
-  public notebookInProgress: boolean = false;
-
-  private subscriptions: Subscription = new Subscription();
-  private clear = undefined;
-
-  @ViewChild('backupDialog') backupDialog;
-  @ViewChild('manageEnvDialog') manageEnvironmentDialog;
-  @ViewChild('keyUploadModal') keyUploadDialog;
-  @ViewChild('preloaderModal') preloaderDialog;
-  @ViewChild('ssnMonitor') ssnMonitorDialog;
-  @ViewChild('rolesGroupsModal') rolesGroupsDialog;
-
-  constructor(
-    private healthStatusService: HealthStatusService,
-    private backupService: BackupService,
-    private manageEnvironmentsService: ManageEnvironmentsService,
-    private userAccessKeyService: UserAccessKeyService,
-    private userResourceService: UserResourceService,
-    private rolesService: RolesGroupsService,
-    private storageService: StorageService,
-    public toastr: ToastrService
-  ) {}
-
-  ngOnInit() {
-    this.buildGrid();
-    this.user = this.storageService.getUserName();
-    this.subscriptions.add(this.userAccessKeyService.accessKeyEmitter
-      .subscribe(result => this.uploadKey = (result && result.status === 200)));
-
-    this.subscriptions.add(this.userAccessKeyService.keyUploadProccessEmitter.subscribe(response => {
-      if (response) this.buildGrid();
-    }));
-  }
-
-  ngOnDestroy(): void {
-    this.subscriptions.unsubscribe();
-  }
-
-  public buildGrid() {
-    this.getEnvironmentHealthStatus();
-  }
-
-  public manageEnvironmentAction($event) {
-    this.manageEnvironmentsService
-      .environmentManagement(
-        $event.environment.user,
-        $event.action,
-        $event.environment.name === 'edge node' ? 'edge' : $event.environment.name,
-        $event.resource ? $event.resource.computational_name : null
-      ).subscribe(
-        () => this.buildGrid(),
-        error => this.toastr.error('Environment management failed!', 'Oops!'));
-  }
-
-  showBackupDialog() {
-    if (!this.backupDialog.isOpened) this.backupDialog.open({ isFooter: false });
-  }
-
-  getActiveUsersList() {
-    return this.healthStatusService.getActiveUsers();
-  }
-
-  getTotalBudgetData() {
-    return this.healthStatusService.getTotalBudgetData();
-  }
-
-  openManageEnvironmentDialog() {
-    this.getActiveUsersList().subscribe(usersList => {
-      this.getTotalBudgetData().subscribe(total => this.manageEnvironmentDialog.open({ isFooter: false }, usersList, total));
-    },
-    () => this.toastr.error('Failed users list loading!', 'Oops!'));
-  }
-
-  openSsnMonitorDialog() {
-    this.healthStatusService.getSsnMonitorData()
-      .subscribe(data => this.ssnMonitorDialog.open({ isFooter: false }, data),
-      () => this.toastr.error('Failed ssn data loading!', 'Oops!'));
-  }
-
-  openManageRolesDialog() {
-    this.rolesService.getGroupsData().subscribe(group => {
-        this.rolesService.getRolesData().subscribe(
-          roles => this.rolesGroupsDialog.open({ isFooter: false }, group, roles),
-          error => this.toastr.error(error.message, 'Oops!'));
-      },
-      error => this.toastr.error(error.message, 'Oops!'));
-  }
-
-  isEnvironmentsInProgress(data): boolean {
-    return data.exploratory.some(el => {
-      return el.status === 'creating' || el.status === 'starting' ||
-        el.computational_resources.some(elem => elem.status === 'creating' || elem.status === 'starting' || elem.status === 'configuring');
-    });
-  }
-
-  isNotebookInProgress(data): boolean {
-    return data.exploratory.some(el => el.status === 'creating');
-  }
-
-  createBackup($event) {
-    this.backupService.createBackup($event).subscribe(result => {
-      this.getBackupStatus(result);
-      this.toastr.success('Backup configuration is processing!', 'Processing!');
-      this.clear = window.setInterval(() => this.getBackupStatus(result), 3000);
-    },
-    error => this.toastr.error(error.message, 'Oops!'));
-  }
-
-  manageRolesGroups($event) {
-    switch ($event.action) {
-      case 'create':
-        this.rolesService.setupNewGroup($event.value).subscribe(res => {
-          this.toastr.success('Group creation success!', 'Created!');
-          this.getGroupsData();
-        }, () => this.toastr.error('Group creation failed!', 'Oops!'));
-        break;
-      case 'update':
-        this.rolesService.updateGroup($event.value).subscribe(res => {
-          this.toastr.success('Group data successfully updated!', 'Success!');
-          this.getGroupsData();
-        }, () => this.toastr.error('Failed group data updating!', 'Oops!'));
-        break;
-      case 'delete':
-        if ($event.type === 'users') {
-          this.rolesService.removeUsersForGroup($event.value).subscribe(res => {
-            this.toastr.success('Users was successfully deleted!', 'Success!');
-            this.getGroupsData();
-          }, () => this.toastr.error('Failed users deleting!', 'Oops!'));
-        } else if ($event.type === 'group') {
-          console.log('delete group');
-          this.rolesService.removeGroupById($event.value).subscribe(res => {
-            this.toastr.success('Group was successfully deleted!', 'Success!');
-            this.getGroupsData();
-          }, () => this.toastr.error('Failed group deleting!', 'Oops!'));
-        }
-        break;
-      default:
-    }
-  }
-
-  setBudgetLimits($event) {
-    this.healthStatusService.updateUsersBudget($event.users).subscribe((result: any) => {
-      this.healthStatusService.updateTotalBudgetData($event.total).subscribe((res: any) => {
-        result.status === HTTP_STATUS_CODES.OK
-        && res.status === HTTP_STATUS_CODES.NO_CONTENT
-        && this.toastr.success('Budget limits updated!', 'Success!');
-        this.buildGrid();
-      });
-    }, error => this.toastr.error(error.message, 'Oops!'));
-  }
-
-  getGroupsData() {
-    this.rolesService.getGroupsData().subscribe(
-      list => this.rolesGroupsDialog.updateGroupData(list),
-      error => this.toastr.error(error.message, 'Oops!'));
-  }
-
-  manageEnvironment(event: {action: string, user: string}) {
-    this.healthStatusService
-      .manageEnvironment(event.action, event.user)
-      .subscribe(res => {
-          this.getActiveUsersList().subscribe(usersList => {
-            this.manageEnvironmentDialog.usersList = usersList;
-            this.toastr.success(`Action ${ event.action } is processing!`, 'Processing!');
-            this.buildGrid();
-          });
-        },
-      error => this.toastr.error(error.message, 'Oops!'));
-  }
-
-  private getExploratoryList() {
-    this.userResourceService.getUserProvisionedResources()
-      .subscribe((result) => {
-        this.anyEnvInProgress = this.isEnvironmentsInProgress(result);
-        this.notebookInProgress = this.isNotebookInProgress(result);
-      });
-  }
-
-  private getBackupStatus(result) {
-    const uuid = result.body;
-    this.backupService.getBackupStatus(uuid)
-      .subscribe((backupStatus: any) => {
-        if (!this.creatingBackup) {
-          backupStatus.status === 'FAILED'
-          ? this.toastr.error('Backup configuration failed!', 'Oops!')
-          : this.toastr.success('Backup configuration completed!', 'Success!');
-          clearInterval(this.clear);
-        }
-      }, () => {
-        clearInterval(this.clear);
-        this.toastr.error('Backup configuration failed!', 'Oops!');
-      });
-  }
-
-  get creatingBackup(): boolean {
-    return this.backupService.inProgress;
-  }
-
-  private getAllEnvironmentData() {
-    this.manageEnvironmentsService
-      .getAllEnvironmentData()
-      .subscribe((result: Array<EnvironmentModel>) => this.allEnvironmentData = this.loadEnvironmentList(result));
-  }
-
-  private loadEnvironmentList(data): Array<EnvironmentModel> {
-    if (data)
-      return data.map(value => new EnvironmentModel(
-          value.resource_name || value.resource_type,
-          value.status,
-          value.shape,
-          value.computational_resources,
-          value.user,
-          value.public_ip,
-          value.resource_type
-        ));
-  }
-
-  private getEnvironmentHealthStatus() {
-    this.healthStatusService
-      .getEnvironmentStatuses()
-      .subscribe((status: GeneralEnvironmentStatus) => {
-        this.healthStatus = status;
-        this.healthStatus.admin && this.getAllEnvironmentData();
-        this.userAccessKeyService.initialUserAccessKeyCheck();
-        this.getExploratoryList();
-      });
-  }
-}
diff --git a/services/self-service/src/main/resources/webapp/src/app/reporting/reporting-grid/reporting-grid.component.html b/services/self-service/src/main/resources/webapp/src/app/reporting/reporting-grid/reporting-grid.component.html
index b468f1e..9472370 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reporting/reporting-grid/reporting-grid.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/reporting/reporting-grid/reporting-grid.component.html
@@ -17,73 +17,135 @@
   ~ under the License.
   -->
 
-<table class="dashboard_table reporting">
-  <tr>
-    <th *ngFor="let column of filteringColumns"
-        ngClass="{{column.className || ''}}"
-        [hidden]="column.role && !full_report">{{ column.title }}
-      <button mat-icon-button *ngIf="column.filtering" aria-label="More" class="ar" (click)="toggleFilterRow()">
-        <i class="material-icons">
-          <span *ngIf="isFiltered && filteredReportData[column.name].length > 0 && !collapseFilterRow">filter_list</span>
-          <span [hidden]="isFiltered && filteredReportData[column.name].length > 0 && !collapseFilterRow">more_vert</span>
-        </i>
-      </button>
-    </th>
-  </tr>
+<section class="table-wrapper" *ngIf="reportData?.lines">
+  <table mat-table [dataSource]="reportData.lines" class="data-grid reporting mat-elevation-z6">
 
-  <tr *ngIf="collapseFilterRow" class="filter-row">
-    <td *ngIf="full_report">
-      <multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="'user'" [items]="filterConfiguration.user" [model]="filteredReportData.user"></multi-select-dropdown>
-    </td>
-    <td>
-      <input type="text" placeholder="Filter by environment name" class="form-control filter-field" [value]="filteredReportData.dlab_id" (input)="filteredReportData.dlab_id = $event.target.value" />
-    </td>
-    <td>
-      <multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="'resource_type'" [items]="filterConfiguration.resource_type" [model]="filteredReportData.resource_type"></multi-select-dropdown>
-    </td>
-    <td>
-      <multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="'status'" [items]="filterConfiguration.status" [model]="filteredReportData.status"></multi-select-dropdown>
-    </td>
-    <td>
-      <multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="[DICTIONARY.billing.instance_size]" [items]="filterConfiguration[DICTIONARY.billing.instance_size]" [model]="filteredReportData[DICTIONARY.billing.instance_size]"></multi-select-dropdown>
-    </td>
-    <td>
-      <multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="[DICTIONARY.billing.service_filter_key]" [items]="filterConfiguration[DICTIONARY.billing.service_filter_key]" [model]="filteredReportData[DICTIONARY.billing.service_filter_key]"></multi-select-dropdown>
-    </td>
-    <td>
-      <div class="actions">
-        <button mat-icon-button class="btn reset" (click)="resetFiltering(); isFiltered = !isFiltered">
-          <i class="material-icons">close</i>
-        </button>
+    <ng-container matColumnDef="name" sticky>
+      <th mat-header-cell *matHeaderCellDef class="env_name"> Environment name </th>
+      <td mat-cell *matCellDef="let element"> {{element[DICTIONARY.billing.dlabId]}} </td>
+      <td mat-footer-cell *matFooterCellDef> Total </td>
+    </ng-container>
 
-        <button mat-icon-button class="btn apply" (click)="filter_btnClick()">
-          <i class="material-icons">done</i>
-        </button>
-      </div>
-    </td>
-  </tr>
+    <ng-container matColumnDef="user">
+      <th mat-header-cell *matHeaderCellDef class="th_user"> User </th>
+      <td mat-cell *matCellDef="let element"> {{element.user}} </td>
+      <td mat-footer-cell *matFooterCellDef></td>
+    </ng-container>
 
-  <ng-template [ngIf]="reportData">
-    <tr *ngFor="let line of reportData" class="dashboard_table_body">
-      <td class="user-field" *ngIf="full_report">{{ line.user }}</td>
-      <td class="env_name">{{ line[DICTIONARY.billing.dlabId] }}</td>
-      <td>{{ line[DICTIONARY.billing.resourceType] }}</td>
-      <td>
-        <span class="status" ngClass="{{ line.status.toLowerCase() || '' }}" *ngIf="line.status">{{ line.status.toLowerCase() }}</span>
-        <span *ngIf="!line.status">N/A</span>
+    <ng-container matColumnDef="type">
+      <th mat-header-cell *matHeaderCellDef class="th_type"> Resource Type </th>
+      <td mat-cell *matCellDef="let element"> {{element[DICTIONARY.billing.resourceType]}} </td>
+      <td mat-footer-cell *matFooterCellDef></td>
+    </ng-container>
+
+    <ng-container matColumnDef="status">
+      <th mat-header-cell *matHeaderCellDef class="th_status"> Status </th>
+      <td mat-cell *matCellDef="let element">
+        <span class="status" ngClass="{{ element.status.toLowerCase() || '' }}"
+          *ngIf="element.status">{{ element.status.toLowerCase() }}</span>
+        <span *ngIf="!element.status">N/A</span>
       </td>
-      <td><span [outerHTML]="line[DICTIONARY.billing.instance_size] | lineBreak"></span></td>
-      <td>{{ line[DICTIONARY.billing.service] }}
-        <span *ngIf="line.resource_type">({{ line.resource_type }})</span>
-      </td>
-      <td>{{ line[DICTIONARY.billing.cost] }} {{ line[DICTIONARY.billing.currencyCode] }}</td>
-    </tr>
-  </ng-template>
-</table>
+      <td mat-footer-cell *matFooterCellDef></td>
+    </ng-container>
 
-<div *ngIf="!reportData" class="message_block message info">
-  <span>To start working, please, create new environment</span>
-</div>
-<div *ngIf="reportData && reportData.length == 0" class="message_block message info">
-  <span>No matches found</span>
-</div>
+    <ng-container matColumnDef="shape">
+      <th mat-header-cell *matHeaderCellDef class="th_shape"> {{ DICTIONARY.instance_size}} </th>
+      <td mat-cell *matCellDef="let element">
+        <span [outerHTML]="element[DICTIONARY.billing.instance_size] | lineBreak"></span>
+      </td>
+      <td mat-footer-cell *matFooterCellDef></td>
+    </ng-container>
+
+    <ng-container matColumnDef="service">
+      <th mat-header-cell *matHeaderCellDef class="service">{{ DICTIONARY.service}}</th>
+      <td mat-cell *matCellDef="let element">
+        {{ element[DICTIONARY.billing.service] }}
+        <span *ngIf="element.resource_type">({{ element.resource_type }})</span>
+      </td>
+      <td mat-footer-cell *matFooterCellDef></td>
+    </ng-container>
+
+    <ng-container matColumnDef="charge" stickyEnd>
+      <th mat-header-cell *matHeaderCellDef class="th_charges"> Service Charges </th>
+
+      <td mat-cell *matCellDef="let element">
+        {{ element[DICTIONARY.billing.cost] }} {{ element[DICTIONARY.billing.currencyCode] }}
+      </td>
+      <td mat-footer-cell *matFooterCellDef>
+        <span *ngIf="reportData">{{ reportData[DICTIONARY.billing.costTotal] }}
+          {{ reportData[DICTIONARY.billing.currencyCode] }}</span>
+      </td>
+    </ng-container>
+
+    <!-- ----------------FILTER -->
+    <ng-container matColumnDef="name-filter" sticky>
+      <th mat-header-cell *matHeaderCellDef>
+        <input type="text" placeholder="Filter by environment name" class="form-control filter-field"
+          [value]="filteredReportData.dlab_id" (input)="filteredReportData.dlab_id = $event.target.value" />
+      </th>
+    </ng-container>
+    <ng-container matColumnDef="user-filter">
+      <th mat-header-cell *matHeaderCellDef>
+        <multi-select-dropdown *ngIf="filterConfiguration" (selectionChange)="onUpdate($event)" [type]="'user'"
+          [items]="filterConfiguration.user" [model]="filteredReportData.user"></multi-select-dropdown>
+      </th>
+    </ng-container>
+    <ng-container matColumnDef="type-filter">
+      <th mat-header-cell *matHeaderCellDef>
+        <multi-select-dropdown *ngIf="filterConfiguration" (selectionChange)="onUpdate($event)" [type]="'resource_type'"
+          [items]="filterConfiguration.resource_type" [model]="filteredReportData.resource_type">
+        </multi-select-dropdown>
+      </th>
+    </ng-container>
+    <ng-container matColumnDef="status-filter">
+      <th mat-header-cell *matHeaderCellDef>
+        <multi-select-dropdown *ngIf="filterConfiguration" (selectionChange)="onUpdate($event)" [type]="'status'"
+          [items]="filterConfiguration.status" [model]="filteredReportData.status"></multi-select-dropdown>
+      </th>
+    </ng-container>
+    <ng-container matColumnDef="shape-filter">
+      <th mat-header-cell *matHeaderCellDef>
+        <multi-select-dropdown *ngIf="filterConfiguration" (selectionChange)="onUpdate($event)"
+          [type]="[DICTIONARY.billing.instance_size]" [items]="filterConfiguration[DICTIONARY.billing.instance_size]"
+          [model]="filteredReportData[DICTIONARY.billing.instance_size]"></multi-select-dropdown>
+      </th>
+    </ng-container>
+    <ng-container matColumnDef="service-filter">
+      <th mat-header-cell *matHeaderCellDef>
+        <multi-select-dropdown *ngIf="filterConfiguration" (selectionChange)="onUpdate($event)"
+          [type]="[DICTIONARY.billing.service_filter_key]"
+          [items]="filterConfiguration[DICTIONARY.billing.service_filter_key]"
+          [model]="filteredReportData[DICTIONARY.billing.service_filter_key]"></multi-select-dropdown>
+      </th>
+    </ng-container>
+    <ng-container matColumnDef="actions" stickyEnd>
+      <th mat-header-cell *matHeaderCellDef>
+        <div class="actions">
+          <button mat-icon-button class="btn reset" (click)="resetFiltering(); isFiltered = !isFiltered">
+            <i class="material-icons">close</i>
+          </button>
+
+          <button mat-icon-button class="btn apply" (click)="filter_btnClick()">
+            <i class="material-icons">done</i>
+          </button>
+        </div>
+      </th>
+    </ng-container>
+    <ng-container matColumnDef="placeholder">
+      <td mat-footer-cell *matFooterCellDef colspan="7" class="info">
+        To start working, please, create new environment
+      </td>
+    </ng-container>
+
+
+    <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
+
+    <ng-container *ngIf="reportData?.lines.length">
+      <tr mat-header-row *matHeaderRowDef="displayedFilterColumns; sticky: true" class="filter-row"></tr>
+
+      <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
+      <tr mat-footer-row *matFooterRowDef="displayedColumns; sticky: true"></tr>
+    </ng-container>
+    <tr [hidden]="reportData?.lines.length" mat-footer-row *matFooterRowDef="['placeholder']"></tr>
+  </table>
+</section>
diff --git a/services/self-service/src/main/resources/webapp/src/app/reporting/reporting-grid/reporting-grid.component.scss b/services/self-service/src/main/resources/webapp/src/app/reporting/reporting-grid/reporting-grid.component.scss
index ed7a79f..5c565bb 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reporting/reporting-grid/reporting-grid.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/reporting/reporting-grid/reporting-grid.component.scss
@@ -17,24 +17,40 @@
  * under the License.
  */
 
-.dashboard_table.reporting {
+.table-wrapper {
+  width: 100%;
+}
+
+.reporting {
+  width: 100%;
+  min-width: 1100px;
+  overflow: auto;
+
   tr {
     th {
       font-size: 11px;
     }
+
     td {
-      font-size: 13px; 
+      font-size: 13px;
     }
+
     &.filter-row {
+      th {
+        padding: 5px;
+      }
+
       .filter-field {
         font-size: 13px;
       }
 
     }
   }
+
   .th_shape {
     width: 10%;
   }
+
   .th_user,
   .env_name,
   .service {
@@ -42,43 +58,54 @@
     overflow: hidden;
     word-wrap: break-word;
   }
+
   .th_type {
     width: 8%;
   }
-  .th_rstatus {
+
+  .th_status {
     width: 8%;
   }
+
   .th_charges {
     width: 8%;
   }
 }
+
 .dashboard_table_body {
   td:first-child {
     cursor: default;
   }
- .dropdown-multiselect {
-  button {
-    font-size: 14px;
-    height: 34px;
-    padding: 7px 20px;
+
+  .dropdown-multiselect {
+    button {
+      font-size: 14px;
+      height: 34px;
+      padding: 7px 20px;
+    }
   }
- }
 }
 
+.no-data {}
+
 @media screen and (max-width: 1280px) {
   .dashboard_table.reporting {
+
     .env_name,
     .service,
     .th_type,
     .th_rstatus {
       width: 10%;
     }
+
     .th_user {
       width: 12%;
     }
+
     .th_charges {
       width: 6%;
     }
+
     .user-field {
       word-wrap: break-word;
     }
diff --git a/services/self-service/src/main/resources/webapp/src/app/reporting/reporting-grid/reporting-grid.component.ts b/services/self-service/src/main/resources/webapp/src/app/reporting/reporting-grid/reporting-grid.component.ts
index f4294a6..c65e01f 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reporting/reporting-grid/reporting-grid.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/reporting/reporting-grid/reporting-grid.component.ts
@@ -25,7 +25,7 @@
   selector: 'dlab-reporting-grid',
   templateUrl: './reporting-grid.component.html',
   styleUrls: ['./reporting-grid.component.scss',
-              '../../resources/resources-grid/resources-grid.component.css']
+    '../../resources/resources-grid/resources-grid.component.css']
 })
 export class ReportingGridComponent implements OnInit {
   readonly DICTIONARY = DICTIONARY;
@@ -33,22 +33,13 @@
   filterConfiguration: ReportingConfigModel;
   filteredReportData: ReportingConfigModel = new ReportingConfigModel([], [], [], [], [], '', '', '');
   collapseFilterRow: boolean = false;
-  reportData: ReportingConfigModel[];
+  reportData: any;
   isFiltered: boolean = false;
-  full_report: boolean = false;
 
   @Output() filterReport: EventEmitter<{}> = new EventEmitter();
   @Output() resetRangePicker: EventEmitter<boolean> = new EventEmitter();
-
-  public filteringColumns: Array<any> = [
-    { title: 'User', name: 'user', className: 'th_user', filtering: true, role: 'admin'},
-    { title: 'Environment name', name: 'dlab_id', className: 'env_name', filtering: true },
-    { title: 'Resource Type', name: 'resource_type', className: 'th_type', filtering: true },
-    { title: 'Status', name: 'status', className: 'th_rstatus', filtering: true },
-    { title: DICTIONARY.instance_size, name: DICTIONARY.billing.instance_size, className: 'th_shape', filtering: true },
-    { title: DICTIONARY.service, name: DICTIONARY.billing.service_filter_key, className: 'service', filtering: true },
-    { title: 'Service Charges', name: 'charges', className: 'th_charges', filtering: false }
-  ];
+  displayedColumns: string[] = ['name', 'user', 'type', 'status', 'shape', 'service', 'charge'];
+  displayedFilterColumns: string[] = ['name-filter', 'user-filter', 'type-filter', 'status-filter', 'shape-filter', 'service-filter', 'actions'];
 
   ngOnInit() { }
 
@@ -56,6 +47,13 @@
     this.filteredReportData[$event.type] = $event.model;
   }
 
+  setFullReport(data): void {
+    if (!data) {
+      this.displayedColumns = this.displayedColumns.filter(el => el !== 'user');
+      this.displayedFilterColumns = this.displayedFilterColumns.filter(el => el !== 'user-filter');
+    }
+  }
+
   toggleFilterRow(): void {
     this.collapseFilterRow = !this.collapseFilterRow;
   }
diff --git a/services/self-service/src/main/resources/webapp/src/app/reporting/reporting.component.ts b/services/self-service/src/main/resources/webapp/src/app/reporting/reporting.component.ts
index 2d34fe4..720b470 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reporting/reporting.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/reporting/reporting.component.ts
@@ -21,7 +21,7 @@
 import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core';
 import { ToastrService } from 'ngx-toastr';
 
-import { BillingReportService, HealthStatusService, UserAccessKeyService } from '../core/services';
+import { BillingReportService, HealthStatusService } from '../core/services';
 import { ReportingGridComponent } from './reporting-grid/reporting-grid.component';
 import { ToolbarComponent } from './toolbar/toolbar.component';
 
@@ -31,14 +31,14 @@
 @Component({
   selector: 'dlab-reporting',
   template: `
-  <dlab-toolbar (rebuildReport)="rebuildBillingReport()"
-                (exportReport)="exportBillingReport()"
-                (setRangeOption)="setRangeOption($event)">
-  </dlab-toolbar>
-  <dlab-reporting-grid (filterReport)="filterReport($event)" (resetRangePicker)="resetRangePicker()"></dlab-reporting-grid>
-  <footer *ngIf="data">
-    Total {{ data[DICTIONARY.billing.costTotal] }} {{ data[DICTIONARY.billing.currencyCode] }}
-  </footer>
+  <div class="base-retreat">
+    <dlab-toolbar (rebuildReport)="rebuildBillingReport()"
+                  (exportReport)="exportBillingReport()"
+                  (setRangeOption)="setRangeOption($event)">
+    </dlab-toolbar>
+    <mat-divider></mat-divider>
+    <dlab-reporting-grid (filterReport)="filterReport($event)" (resetRangePicker)="resetRangePicker()"></dlab-reporting-grid>
+  </div>
 
   `,
   styles: [`
@@ -65,14 +65,12 @@
   reportData: ReportingConfigModel = ReportingConfigModel.getDefault();
   filterConfiguration: ReportingConfigModel = ReportingConfigModel.getDefault();
   data: any;
-  healthStatus: any;
   billingEnabled: boolean;
   admin: boolean;
 
   constructor(
     private billingReportService: BillingReportService,
     private healthStatusService: HealthStatusService,
-    private userAccessKeyService: UserAccessKeyService,
     public toastr: ToastrService
   ) {}
 
@@ -89,8 +87,8 @@
     this.billingReportService.getGeneralBillingData(this.reportData)
       .subscribe(data => {
         this.data = data;
-        this.reportingGrid.reportData = this.data.lines;
-        this.reportingGrid.full_report = this.data.full_report;
+        this.reportingGrid.reportData = this.data;
+        this.reportingGrid.setFullReport(this.data.full_report);
 
         this.reportingToolbar.reportData = this.data;
         if (!localStorage.getItem('report_period')) {
@@ -177,25 +175,22 @@
     this.reportingToolbar.clearRangePicker();
   }
 
-  clearStorage(): void {
-    localStorage.removeItem('report_config');
-    localStorage.removeItem('report_period');
-  }
-
   setRangeOption(dateRangeOption: any): void {
     this.reportData.date_start = dateRangeOption.start_date;
     this.reportData.date_end = dateRangeOption.end_date;
     this.getGeneralBillingData();
   }
 
+  private clearStorage(): void {
+    localStorage.removeItem('report_config');
+    localStorage.removeItem('report_period');
+  }
+
   private getEnvironmentHealthStatus() {
     this.healthStatusService.getEnvironmentHealthStatus()
       .subscribe((result: any) => {
-        this.healthStatus = result.status;
         this.billingEnabled = result.billingEnabled;
         this.admin = result.admin;
-
-        this.userAccessKeyService.initialUserAccessKeyCheck();
       });
   }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/reporting/reporting.module.ts b/services/self-service/src/main/resources/webapp/src/app/reporting/reporting.module.ts
index eea9fb5..3067e9a 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reporting/reporting.module.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/reporting/reporting.module.ts
@@ -22,11 +22,9 @@
 import { FormsModule } from '@angular/forms';
 import { NgDateRangePickerModule } from 'ng-daterangepicker';
 
-import { NgxMatDrpModule } from 'ngx-mat-daterange-picker';
 import { MaterialModule } from '../shared/material.module';
 import { FormControlsModule } from '../shared/form-controls';
 import { ReportingComponent } from './reporting.component';
-import { ModalModule, UploadKeyDialogModule, ProgressDialogModule } from '../shared';
 import { KeysPipeModule, LineBreaksPipeModule } from '../core/pipes';
 import { ReportingGridComponent } from './reporting-grid/reporting-grid.component';
 import { ToolbarComponent } from './toolbar/toolbar.component';
@@ -34,15 +32,11 @@
 @NgModule({
   imports: [
     CommonModule,
-    ModalModule,
     FormsModule,
     FormControlsModule,
     KeysPipeModule,
     LineBreaksPipeModule,
-    NgxMatDrpModule,
     NgDateRangePickerModule,
-    UploadKeyDialogModule,
-    ProgressDialogModule,
     MaterialModule
   ],
   declarations: [
diff --git a/services/self-service/src/main/resources/webapp/src/app/reporting/toolbar/toolbar.component.css b/services/self-service/src/main/resources/webapp/src/app/reporting/toolbar/toolbar.component.css
index d520b8a..5e82739 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reporting/toolbar/toolbar.component.css
+++ b/services/self-service/src/main/resources/webapp/src/app/reporting/toolbar/toolbar.component.css
@@ -20,7 +20,6 @@
 section {
     display: flex;
     justify-content: space-between;
-    padding: 10px 15px;
     font-weight: 300;
 }
 section > div {
diff --git a/services/self-service/src/main/resources/webapp/src/app/reporting/toolbar/toolbar.component.html b/services/self-service/src/main/resources/webapp/src/app/reporting/toolbar/toolbar.component.html
index c7f16d5..e425338 100644
--- a/services/self-service/src/main/resources/webapp/src/app/reporting/toolbar/toolbar.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/reporting/toolbar/toolbar.component.html
@@ -22,7 +22,8 @@
       <div><span>Service base name: </span><strong>{{ reportData.service_base_name }}</strong></div>
       <div *ngIf="reportData.tag_resource_id"><span>Resource tag ID: </span><strong>{{ reportData.tag_resource_id }}</strong></div>
       <div class="report-period info_color" *ngIf="availablePeriodFrom && availablePeriodTo">
-        Available reporting period from: <strong>{{ availablePeriodFrom | date }} </strong>
+        <span>Available reporting period from:</span>
+        <strong>{{ availablePeriodFrom | date }} </strong>
         to: <strong>{{ availablePeriodTo | date }}</strong>
       </div>
     </div>
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 ec62674..a131587 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
@@ -17,9 +17,11 @@
   ~ under the License.
   -->
 
-<modal-dialog #bindDialog  modalClass="detail-dialog modal-sm header-white">
-  <modal-header></modal-header>
-  <modal-content>
+<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 class="dialog-content">
     <div *ngIf="resource">
       <table class="detail-header">
         <tr>
@@ -99,7 +101,7 @@
           </small>
         </div>
         <div class="text-center m-top-30" *ngIf="configuration?.nativeElement['checked'] || false">
-          <button mat-raised-button type="button" (click)="bindDialog.close()" class="butt action">Cancel</button>
+          <button mat-raised-button type="button" (click)="dialogRef.close()" class="butt action">Cancel</button>
           <button mat-raised-button type="submit" [disabled]="!configurationForm.valid"
                   class="butt butt-success action" [ngClass]="{'not-allowed': !configurationForm.valid}"
                   (click)="editClusterConfiguration(configurationForm.value)">Update</button>
@@ -111,5 +113,5 @@
         <p class="failed">{{resource.error_message}}</p>
       </div>
     </div>
-  </modal-content>
-</modal-dialog>
+  </div>
+</div>
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 2bcf5af..186c519 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
@@ -17,12 +17,12 @@
  * under the License.
  */
 
-import { Component, ViewChild, OnInit, Output, EventEmitter } from '@angular/core';
-import { DateUtils } from '../../../core/util';
+import { Component, ViewChild, OnInit, Inject } from '@angular/core';
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
 import { FormGroup, FormBuilder } from '@angular/forms';
 import { ToastrService } from 'ngx-toastr';
 
-import { CheckUtils } from '../../../core/util';
+import { DateUtils, CheckUtils } from '../../../core/util';
 import { DataengineConfigurationService } from '../../../core/services';
 import { DICTIONARY } from '../../../../dictionary/global.dictionary';
 import { CLUSTER_CONFIGURATION } from '../computational-resource-create-dialog/cluster-configuration-templates';
@@ -38,7 +38,6 @@
 
   resource: any;
   environment: any;
-  @ViewChild('bindDialog') bindDialog;
   @ViewChild('configurationNode') configuration;
 
   upTimeInHours: number;
@@ -47,19 +46,20 @@
   config: Array<{}> = [];
   public configurationForm: FormGroup;
 
-  @Output() buildGrid: EventEmitter<{}> = new EventEmitter();
-
   constructor(
+    @Inject(MAT_DIALOG_DATA) public data: any,
+    public toastr: ToastrService,
+    public dialogRef: MatDialogRef<DetailComputationalResourcesComponent>,
     private dataengineConfigurationService: DataengineConfigurationService,
-    private _fb: FormBuilder,
-    public toastr: ToastrService
+    private _fb: FormBuilder
   ) {}
 
   ngOnInit() {
-    this.bindDialog.onClosing = () => this.resetDialog();
+    // this.bindDialog.onClosing = () => this.resetDialog();
+    this.open(this.data.environment, this.data.resource)
   }
 
-  public open(param, environment, resource): void {
+  public open(environment, resource): void {
     this.tooltip = false;
     this.resource = resource;
     this.environment = environment;
@@ -69,7 +69,6 @@
     this.initFormModel();
 
     if (this.resource.image === 'docker.dlab-dataengine') this.getClusterConfiguration();
-    this.bindDialog.open(param);
   }
 
   public isEllipsisActive($event): void {
@@ -98,8 +97,7 @@
     this.dataengineConfigurationService
       .editClusterConfiguration(data.configuration_parameters, this.environment.name, this.resource.computational_name)
       .subscribe(result => {
-        this.bindDialog.close();
-        this.buildGrid.emit();
+        this.dialogRef.close();
       },
       error => this.toastr.error(error.message || 'Edit onfiguration failed!', 'Oops!'));
   }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/index.ts b/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/index.ts
index b81e2e7..88bfff6 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/cluster-details/index.ts
@@ -21,15 +21,15 @@
 import { CommonModule } from '@angular/common';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 
-import { ModalModule } from '../../../shared';
 import { MaterialModule } from '../../../shared/material.module';
 import { DetailComputationalResourcesComponent } from './cluster-details.component';
 
 export * from './cluster-details.component';
 
 @NgModule({
-  imports: [CommonModule, ModalModule, FormsModule, ReactiveFormsModule, MaterialModule],
+  imports: [CommonModule, FormsModule, ReactiveFormsModule, MaterialModule],
   declarations: [DetailComputationalResourcesComponent],
+  entryComponents: [DetailComputationalResourcesComponent],
   exports: [DetailComputationalResourcesComponent],
 })
 
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 dcf1c25..79822d8 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
@@ -17,97 +17,148 @@
   ~ under the License.
   -->
 
-<modal-dialog #bindDialog modalClass="create-cluster modal-xxl">
-  <modal-header>
+<div class="create-cluster" id="dialog-box">
+  <header class="dialog-header">
     <h4 class="modal-title">Add computational resources</h4>
-  </modal-header>
-  <modal-content>
-    <div class="content-box">
-      <form [formGroup]="resourceForm"
-            (submit)="createComputationalResource($event, resourceForm.value, shapes.master_shape, shapes.slave_shape)"
-            *ngIf="model.availableTemplates && resourceForm">
+    <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+  </header>
+  <div class="dialog-content selection">
+    <div class="content-box mat-reset">
+      <form [formGroup]="resourceForm" *ngIf="clusterTypes.length && resourceForm; else empty">
 
-        <div class="form-wrapper" [ngClass]="{ compress: model.selectedImage?.image === 'docker.dlab-dataengine' }">
+        <div class="form-wrapper" [ngClass]="{ compress: selectedImage?.image === 'docker.dlab-dataengine' }">
           <div class="col">
 
-              <div class="control-group" *ngIf="PROVIDER !== 'azure'" [hidden]="model.resourceImages.length === 1">
-                <label class="label">Select cluster type</label>
-                <div class="control">
-                  <dropdown-list #clusterType (selectedItem)="onUpdate($event)"></dropdown-list>
-                </div>
-                <!-- <div class="mt-5" *ngIf="model.resourceImages">
-                  <small *ngIf="model.selectedImage">{{ model.selectedImage.description }}</small>
-                </div> -->
+            <div class="control-group" *ngIf="PROVIDER !== 'azure'" [hidden]="clusterTypes.length === 1">
+              <label class="label">Select cluster type</label>
+              <div class="control selector-wrapper">
+                <mat-form-field>
+                  <mat-label>Select cluster type</mat-label>
+                  <mat-select formControlName="template_name" disableOptionCentering>
+                    <mat-option *ngFor="let type of clusterTypes" [value]="type.template_name"
+                      (click)="selectImage(type)">{{ type.template_name }}</mat-option>
+                    <mat-option *ngIf="!clusterTypes.length" class="multiple-select ml-10" disabled>Clusters types list
+                      is empty</mat-option>
+                  </mat-select>
+                  <button class="caret">
+                    <i class="material-icons">keyboard_arrow_down</i>
+                  </button>
+                </mat-form-field>
               </div>
+            </div>
 
-              <div class="control-group" *ngIf="PROVIDER !== 'azure'" [hidden]="!model.templates.length">
-                <label class="label">Select template</label>
-                <div class="control">
-                  <dropdown-list #templatesList (selectedItem)="onUpdate($event)"></dropdown-list>
-                </div>
+            <div class="control-group" *ngIf="PROVIDER !== 'azure'" [hidden]="!selectedImage.templates.length">
+              <label class="label">Select template</label>
+              <div class="control selector-wrapper">
+                <mat-form-field>
+                  <mat-label>Select template</mat-label>
+                  <mat-select formControlName="version" disableOptionCentering>
+                    <mat-option *ngFor="let template of selectedImage.templates" [value]="template.version">
+                      {{ template.version }}</mat-option>
+                    <mat-option *ngIf="!selectedImage.templates" class="multiple-select ml-10" disabled>Templates list
+                      is empty</mat-option>
+                  </mat-select>
+                  <button class="caret">
+                    <i class="material-icons">keyboard_arrow_down</i>
+                  </button>
+                </mat-form-field>
               </div>
+            </div>
 
-              <div class="control-group alias-name" *ngIf="model.selectedImage?.image">
-                <label class="label">Cluster alias</label>
-                <div class="control">
-                    <input [class.danger_field]="computationalResourceExist || !resourceForm?.controls['cluster_alias_name'].valid
-                          && resourceForm?.controls['cluster_alias_name'].dirty && resourceForm?.controls['cluster_alias_name'].hasError('duplication')"
-                          type="text" class="form-control" placeholder="Enter cluster alias" formControlName="cluster_alias_name" />
-                    <span class="danger_color" *ngIf="resourceForm?.controls['cluster_alias_name'].hasError('duplication')">This cluster name already exists.</span>
-                    <span class="danger_color" *ngIf="!resourceForm?.controls.cluster_alias_name.valid
-                                              && resourceForm?.controls['cluster_alias_name'].dirty
-                                              && !resourceForm?.controls['cluster_alias_name'].hasError('duplication')">
-                      Cluster name <span *ngIf="DICTIONARY.cloud_provider !== 'aws'">cannot be longer than 10 characters and</span> can only contain letters, numbers, hyphens and '_' but can not end with special characters
-                    </span>
-                </div>
-              </div>
-
-
-          </div>
-          <div class="col">
-            <div class="control-group" *ngIf="model.selectedImage?.image">
-              <label class="label">{{ DICTIONARY[model.selectedImage.image].instance_number }}</label>
+            <div class="control-group alias-name" *ngIf="selectedImage?.image">
+              <label class="label">Cluster alias</label>
               <div class="control">
-                <input type="number" class="form-control" min="{{minInstanceNumber}}" max="{{maxInstanceNumber}}"
-                      formControlName="instance_number" (keypress)="CheckUtils.isNumberKey($event)" />
-                <span class="danger_color" *ngIf="!resourceForm?.controls.instance_number.valid">
-                  <span>Only integer values greater than or equal to {{ minInstanceNumber }} and less than {{ maxInstanceNumber }} are allowed</span>
+                <input
+                  [class.danger_field]="computationalResourceExist || !resourceForm?.controls['cluster_alias_name'].valid
+                        && resourceForm?.controls['cluster_alias_name'].dirty && resourceForm?.controls['cluster_alias_name'].hasError('duplication')"
+                  type="text" class="form-control" placeholder="Enter cluster alias"
+                  formControlName="cluster_alias_name" />
+                <span class="error" *ngIf="resourceForm?.controls['cluster_alias_name'].hasError('duplication')">This
+                  cluster name already exists.</span>
+                <span class="error" *ngIf="!resourceForm?.controls.cluster_alias_name.valid
+                                            && resourceForm?.controls['cluster_alias_name'].dirty
+                                            && !resourceForm?.controls['cluster_alias_name'].hasError('duplication')">
+                  Cluster name <span *ngIf="DICTIONARY.cloud_provider !== 'aws'">cannot be longer than 10 characters
+                    and</span> can only contain letters, numbers, hyphens and '_' but can not end with special
+                  characters
                 </span>
               </div>
             </div>
-            <div class="control-group" *ngIf="model.selectedImage?.image">
-              <label class="label" *ngIf="model.selectedImage">{{ DICTIONARY[model.selectedImage.image].data_engine_master_instance_size}}</label>
+          </div>
+
+          <div class="col">
+            <div class="control-group" *ngIf="selectedImage?.image">
+              <label class="label">{{ DICTIONARY[selectedImage.image].instance_number }}</label>
               <div class="control">
-                <dropdown-list #masterShapesList (selectedItem)="onUpdate($event)"></dropdown-list>
+                <input type="number" class="form-control" min="{{minInstanceNumber}}" max="{{maxInstanceNumber}}"
+                  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
+                    {{ maxInstanceNumber }} are allowed</span>
+                </span>
               </div>
             </div>
 
-            <div class="control-group" *ngIf="model.selectedImage?.image" [hidden]="model.selectedImage?.image === 'docker.dlab-dataengine'">
-              <label class="label">{{ DICTIONARY[model.selectedImage.image].data_engine_slave_instance_size }}</label>
-              <div class="control">
-                <dropdown-list #shapesSlaveList (selectedItem)="onUpdate($event)"></dropdown-list>
+            <div class="control-group" *ngIf="selectedImage?.image">
+              <label class="label">{{ DICTIONARY[selectedImage.image].data_engine_master_instance_size }}</label>
+              <div class="control selector-wrapper">
+                <mat-form-field>
+                  <mat-label>Select {{ DICTIONARY.notebook_instance_size }}</mat-label>
+                  <mat-select formControlName="shape_master" disableOptionCentering>
+                    <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">
+                        <strong class="highlight icon-label">{{ list_item.Size }}</strong> {{ list_item.Type }}
+                      </mat-option>
+                    </mat-optgroup>
+                  </mat-select>
+                  <button class="caret">
+                    <i class="material-icons">keyboard_arrow_down</i>
+                  </button>
+                </mat-form-field>
               </div>
             </div>
+
+            <div class="control-group" *ngIf="selectedImage?.image"
+              [hidden]="selectedImage?.image === 'docker.dlab-dataengine'">
+              <label class="label">{{ DICTIONARY[selectedImage.image].data_engine_slave_instance_size }}</label>
+              <div class="control selector-wrapper">
+                <mat-form-field>
+                  <mat-label>Select {{ DICTIONARY.notebook_instance_size }}</mat-label>
+                  <mat-select formControlName="shape_slave" disableOptionCentering>
+                    <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">
+                        <strong class="highlight icon-label">{{ list_item.Size }}</strong> {{ list_item.Type }}
+                      </mat-option>
+                    </mat-optgroup>
+                  </mat-select>
+                  <button class="caret">
+                    <i class="material-icons">keyboard_arrow_down</i>
+                  </button>
+                </mat-form-field>
+              </div>
+            </div>
+
           </div>
         </div>
 
-        <div class="preemptible checkbox-group control-group m-top-30 m-bott-10" *ngIf="PROVIDER === 'gcp' && model.selectedImage?.image === 'docker.dlab-dataengine-service'">
+        <div class="preemptible checkbox-group control-group m-top-30 m-bott-10"
+          *ngIf="PROVIDER === 'gcp' && selectedImage?.image === 'docker.dlab-dataengine-service'">
           <label class="label">
             <input #preemptibleNode type="checkbox" (change)="selectPreemptibleNodes($event)" />
             <span>Preemptible node</span>
             <span class="align" *ngIf="preemptible?.nativeElement['checked'] || false"> count</span>
           </label>
-          <div *ngIf="preemptible?.nativeElement['checked']"
-                class="preemptible-details control"
-                [ngClass]="{ show: preemptible?.nativeElement['checked'] || false}">
-            <input type="text" class="form-control"
-              formControlName="preemptible_instance_number"
-              (keypress)="CheckUtils.isNumberKey($event)"
-              (keydown.arrowup)="preemptibleCounter($event, 'increment')"
+          <div *ngIf="preemptible?.nativeElement['checked']" class="preemptible-details control"
+            [ngClass]="{ show: preemptible?.nativeElement['checked'] || false}">
+            <input type="text" class="form-control" formControlName="preemptible_instance_number"
+              (keypress)="CheckUtils.isNumberKey($event)" (keydown.arrowup)="preemptibleCounter($event, 'increment')"
               (keydown.arrowdown)="preemptibleCounter($event, 'decrement')" />
-            <span class="danger_color" *ngIf="!resourceForm?.controls.preemptible_instance_number.valid">
+            <span class="error" *ngIf="!resourceForm?.controls.preemptible_instance_number.valid">
               <span *ngIf="minPreemptibleInstanceNumber !== maxPreemptibleInstanceNumber; else equal">
-                Only integer values greater than or equal to {{ minPreemptibleInstanceNumber }} and less than {{ maxPreemptibleInstanceNumber }} are allowed
+                Only integer values greater than or equal to {{ minPreemptibleInstanceNumber }} and less than
+                {{ maxPreemptibleInstanceNumber }} are allowed
               </span>
               <ng-template #equal>Please manage total machines count</ng-template>
             </span>
@@ -115,52 +166,69 @@
         </div>
 
         <div class="checkbox-group control-group m-top-15" *ngIf="PROVIDER === 'aws'"
-            [hidden]="!model.templates.length || !isAvailableSpots()">
+          [hidden]="!selectedImage.templates.length">
           <label class="spot-label label">
             <input #spotInstancesCheck type="checkbox" (change)="selectSpotInstances($event)" />
             <span>Spot instance</span>
-            <span *ngIf="spotInstancesSelect?.nativeElement['checked'] || false"> bit, %</span>
+            <span *ngIf="spotInstancesSelect?.nativeElement['checked'] || false"> bid, %</span>
           </label>
-          <div class="control spot-details" [ngClass]="{ show: spotInstancesSelect?.nativeElement['checked'] || false }" *ngIf="spotInstancesSelect?.nativeElement['checked'] || false">
-            <input type="number" class="form-control" step="5" min="{{minSpotPrice}}" max="{{maxSpotPrice}}" formControlName="instance_price" (keypress)="CheckUtils.isNumberKey($event)">
-            <span class="danger_color" *ngIf="!resourceForm?.controls.instance_price.valid">
+          <div class="control spot-details" [ngClass]="{ show: spotInstancesSelect?.nativeElement['checked'] || false }"
+            *ngIf="spotInstancesSelect?.nativeElement['checked'] || false">
+            <input type="number" class="form-control" step="5" min="{{minSpotPrice}}" max="{{maxSpotPrice}}"
+              formControlName="instance_price" (keypress)="CheckUtils.isNumberKey($event)">
+            <span class="error" *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" *ngIf="spotInstancesSelect?.nativeElement['checked'] || false">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>
+          <span class="info" *ngIf="spotInstancesSelect?.nativeElement['checked'] || false">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 class="checkbox-group" [hidden]="PROVIDER === 'gcp' && model.selectedImage?.image === 'docker.dlab-dataengine-service'"
-             *ngIf="notebook_instance?.image !== 'docker.dlab-zeppelin'">
+        <div class="checkbox-group m-top-20"
+          [hidden]="PROVIDER === 'gcp' && selectedImage?.image === 'docker.dlab-dataengine-service'"
+          *ngIf="notebook_instance?.image !== 'docker.dlab-zeppelin'">
           <label>
-            <input #configurationNode type="checkbox" (change)="selectConfiguration()"/> Cluster configurations
+            <input #configurationNode type="checkbox" (change)="selectConfiguration()" /> Cluster configurations
           </label>
           <div class="config-link" *ngIf="(configuration?.nativeElement['checked'] || false)
-            && model.selectedImage?.image === 'docker.dlab-dataengine-service'
+            && selectedImage?.image === 'docker.dlab-dataengine-service'
             && DICTIONARY.cloud_provider === 'aws'">
-            To view example JSON of configurations refer for <a href="https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-configure-apps.html" target="_blank">AWS official documentation</a>
+            To view example JSON of configurations refer for <a
+              href="https://docs.aws.amazon.com/emr/latest/ReleaseGuide/emr-configure-apps.html" target="_blank">AWS
+              official documentation</a>
           </div>
         </div>
         <div class="checkbox-group">
           <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="!resourceForm?.controls.configuration_parameters.valid && resourceForm?.controls['configuration_parameters'].dirty">Configuration parameters is not in a valid format</span>
+            <textarea formControlName="configuration_parameters" placeholder="Cluster configuration template, JSON"
+              data-gramm_editor="false"></textarea>
+            <span class="error"
+              *ngIf="!resourceForm?.controls.configuration_parameters.valid && resourceForm?.controls['configuration_parameters'].dirty">Configuration
+              parameters is not in a valid format</span>
           </div>
         </div>
         <div *ngIf="notebook_instance?.image === 'docker.dlab-zeppelin'">
-          <small>Spark default configuration for Apache Zeppelin can not be changed from DLab 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.8.0/usage/interpreter/overview.html" target="_blank">official documentation</a>.
+          <small>Spark default configuration for Apache Zeppelin can not be changed from DLab 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.8.0/usage/interpreter/overview.html" target="_blank">official
+              documentation</a>.
           </small>
         </div>
         <div class="text-center m-top-30">
-          <button mat-raised-button type="button" (click)="bindDialog.close()" class="butt action">Cancel</button>
-          <button mat-raised-button type="submit" [disabled]="!resourceForm?.valid"
-                  class="butt butt-success action" [ngClass]="{'not-allowed': !resourceForm?.valid}">Create</button>
+          <button mat-raised-button type="button" (click)="dialogRef.close()" class="butt action">Cancel</button>
+          <button mat-raised-button type="button" [disabled]="!resourceForm?.valid"
+            (click)="createComputationalResource(resourceForm.value)" class="butt butt-success action"
+            [ngClass]="{'not-allowed': !resourceForm?.valid}">Create</button>
         </div>
       </form>
 
-      <div *ngIf="!model.availableTemplates" class="info message">Computational resource creations are not available.<br>Please, check your permissions.</div>
+      <ng-template #empty>
+        <div class="info message">Computational resource creations are not available.<br>Please, check your permissions.
+        </div>
+      </ng-template>
     </div>
-  </modal-content>
-</modal-dialog>
+  </div>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.scss
index 9ccc51f..c40a785 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resource-create-dialog/computational-resource-create-dialog.component.scss
@@ -32,11 +32,11 @@
       }
     }
     span {
-      &.danger_color {
+      &.error {
         position: absolute;
         padding-left: 5px;
         right: 0;
-        top: 40px;
+        top: 36px;
       }
     }
     .alias-name {
@@ -86,7 +86,7 @@
   }
   .spot-details, .preemptible-details {
     position: relative;
-    .danger_color {
+    .error {
       bottom: -5px;
     }
 
@@ -118,7 +118,7 @@
     cursor: pointer;
   }
   span {
-    &.danger_color {
+    &.error {
       position: absolute;
       bottom: -20px;
       left: 0;
@@ -135,7 +135,7 @@
       padding-bottom: 10px;
     }
     span {
-      &.danger_color {
+      &.error {
         position: absolute;
         bottom: -15px;
         right: 0;
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 6acc684..761ca2e 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,13 +17,14 @@
  * under the License.
  */
 
-import { Component, OnInit, EventEmitter, Output, ViewChild, ChangeDetectorRef } from '@angular/core';
+import { Component, OnInit, ViewChild, Inject } from '@angular/core';
 import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
 import { ToastrService } from 'ngx-toastr';
 
-import { ComputationalResourceCreateModel } from './computational-resource-create.model';
+import { ComputationalResourceModel } from './computational-resource-create.model';
 import { UserResourceService } from '../../../core/services';
-import { HTTP_STATUS_CODES, CheckUtils } from '../../../core/util';
+import { HTTP_STATUS_CODES, PATTERNS, CheckUtils } from '../../../core/util';
 
 import { DICTIONARY } from '../../../../dictionary/global.dictionary';
 import { CLUSTER_CONFIGURATION } from './cluster-configuration-templates';
@@ -40,16 +41,11 @@
   readonly CLUSTER_CONFIGURATION = CLUSTER_CONFIGURATION;
   readonly CheckUtils = CheckUtils;
 
-  model: ComputationalResourceCreateModel;
   notebook_instance: any;
-  full_list: any;
-  template_description: string;
-  shapes: any;
+  resourcesList: any;
+  clusterTypes = [];
+  selectedImage: any;
   spotInstance: boolean = true;
-  clusterNamePattern: string = '[-_a-zA-Z0-9]*[_-]*[a-zA-Z0-9]+';
-  nodeCountPattern: string = '^[1-9]\\d*$';
-  delimitersRegex = /[-_]?/g;
-  integerRegex = '^[0-9]*$';
 
   public minInstanceNumber: number;
   public maxInstanceNumber: number;
@@ -59,115 +55,40 @@
   public maxSpotPrice: number = 0;
   public resourceForm: FormGroup;
 
-  @ViewChild('bindDialog') bindDialog;
-  @ViewChild('name') name;
-  @ViewChild('clusterType') cluster_type;
-  @ViewChild('templatesList') templates_list;
-  @ViewChild('masterShapesList') master_shapes_list;
-  @ViewChild('shapesSlaveList') slave_shapes_list;
   @ViewChild('spotInstancesCheck') spotInstancesSelect;
   @ViewChild('preemptibleNode') preemptible;
   @ViewChild('configurationNode') configuration;
 
-  @Output() buildGrid: EventEmitter<{}> = new EventEmitter();
-
   constructor(
+    @Inject(MAT_DIALOG_DATA) public data: any,
+    public toastr: ToastrService,
+    public dialogRef: MatDialogRef<ComputationalResourceCreateDialogComponent>,
     private userResourceService: UserResourceService,
-    private _fb: FormBuilder,
-    private ref: ChangeDetectorRef,
-    public toastr: ToastrService
-  ) {
-    this.model = ComputationalResourceCreateModel.getDefault(userResourceService);
-  }
+    private model: ComputationalResourceModel,
+    private _fb: FormBuilder
+  ) { }
 
   ngOnInit() {
+    this.notebook_instance = this.data.notebook;
+    this.resourcesList = this.data.full_list;
     this.initFormModel();
-    this.bindDialog.onClosing = () => this.resetDialog();
+    this.getTemplates(this.notebook_instance.project);
   }
 
-  // public isNumberKey($event): boolean {
-  //   const charCode = ($event.which) ? $event.which : $event.keyCode;
-  //   if (charCode !== 46 && charCode > 31 && (charCode < 48 || charCode > 57)) {
-  //     $event.preventDefault();
-  //     return false;
-  //   }
-  //   return true;
-  // }
+  public selectImage($event) {
+    this.selectedImage = $event;
+    this.getComputationalResourceLimits();
 
-  public onUpdate($event): void {
-    if ($event.model.type === 'template') {
-      this.model.setSelectedTemplate($event.model.index);
-      this.master_shapes_list.setDefaultOptions(this.model.selectedImage.shapes.resourcesShapeTypes,
-        this.shapePlaceholder(this.model.selectedImage.shapes.resourcesShapeTypes, 'description'), 'master_shape', 'description', 'json');
-      this.slave_shapes_list.setDefaultOptions(this.model.selectedImage.shapes.resourcesShapeTypes,
-        this.shapePlaceholder(this.model.selectedImage.shapes.resourcesShapeTypes, 'description'), 'slave_shape', 'description', 'json');
-
-      this.shapes.master_shape = this.shapePlaceholder(this.model.selectedImage.shapes.resourcesShapeTypes, 'type');
-      this.shapes.slave_shape = this.shapePlaceholder(this.model.selectedImage.shapes.resourcesShapeTypes, 'type');
-    }
-    if ($event.model.type === 'cluster_type') {
-      this.model.setSelectedClusterType($event.model.index);
-      this.setDefaultParams();
-      this.getComputationalResourceLimits();
-      this.selectConfiguration();
-    }
-
-    if (this.shapes[$event.model.type])
-      this.shapes[$event.model.type] = $event.model.value.type;
-
-    if (DICTIONARY.cloud_provider === 'aws')
-      if ($event.model.type === 'slave_shape' && this.spotInstancesSelect.nativeElement['checked']) {
-        this.spotInstance = $event.model.value.spot;
-      }
-  }
-
-  public createComputationalResource($event, data, shape_master: string, shape_slave: string) {
-    this.model.setCreatingParams(
-      data.cluster_alias_name,
-      data.instance_number,
-      shape_master, shape_slave,
-      this.spotInstance,
-      data.instance_price,
-      data.preemptible_instance_number,
-      data.configuration_parameters ? JSON.parse(data.configuration_parameters) : null);
-    this.model.confirmAction();
-    $event.preventDefault();
-    return false;
-  }
-
-  public containsComputationalResource(conputational_resource_name: string): boolean {
-    if (conputational_resource_name)
-      for (let index = 0; index < this.full_list.length; index++) {
-        if (this.notebook_instance.name === this.full_list[index].name) {
-          for (let iindex = 0; iindex < this.full_list[index].resources.length; iindex++) {
-            const computational_name = this.full_list[index].resources[iindex].computational_name.toString().toLowerCase();
-            if (this.delimitersFiltering(conputational_resource_name) === this.delimitersFiltering(computational_name))
-              return true;
-          }
-        }
-      }
-    return false;
-  }
-
-  public delimitersFiltering(resource): string {
-    return resource.replace(this.delimitersRegex, '').toString().toLowerCase();
+    if ($event.templates)
+      this.resourceForm.controls['version'].setValue($event.templates[0].version)
   }
 
   public selectSpotInstances($event?): void {
-    if ($event ? $event.target.checked : this.spotInstancesSelect.nativeElement['checked']) {
+    if ($event ? $event.target.checked : (this.spotInstancesSelect && this.spotInstancesSelect.nativeElement['checked'])) {
       const filtered = this.filterAvailableSpots();
-
-      this.slave_shapes_list.setDefaultOptions(filtered, this.shapePlaceholder(filtered, 'description'),
-        'slave_shape', 'description', 'json');
-      this.shapes.slave_shape = this.shapePlaceholder(filtered, 'type');
-
       this.spotInstance = this.shapePlaceholder(filtered, 'spot');
       this.resourceForm.controls['instance_price'].setValue(50);
     } else {
-      this.slave_shapes_list.setDefaultOptions(this.model.selectedImage.shapes.resourcesShapeTypes,
-        this.shapePlaceholder(this.model.selectedImage.shapes.resourcesShapeTypes, 'description'), 'slave_shape', 'description', 'json');
-      this.shapes.slave_shape = this.shapePlaceholder(this.model.selectedImage.shapes.resourcesShapeTypes, 'type');
-
       this.spotInstance = false;
       this.resourceForm.controls['instance_price'].setValue(0);
     }
@@ -180,7 +101,7 @@
 
   public selectConfiguration() {
     if (this.configuration && this.configuration.nativeElement.checked) {
-      const template = (this.model.selectedImage.image === 'docker.dlab-dataengine-service')
+      const template = (this.selectedImage.image === 'docker.dlab-dataengine-service')
         ? CLUSTER_CONFIGURATION.EMR
         : CLUSTER_CONFIGURATION.SPARK;
       this.resourceForm.controls['configuration_parameters'].setValue(JSON.stringify(template, undefined, 2));
@@ -189,50 +110,6 @@
     }
   }
 
-  private filterAvailableSpots() {
-    const filtered = JSON.parse(JSON.stringify(this.slave_shapes_list.items));
-    for (const item in this.slave_shapes_list.items) {
-        filtered[item] = filtered[item].filter(el => el.spot);
-        if (filtered[item].length <= 0) {
-          delete filtered[item];
-        }
-    }
-    return filtered;
-  }
-
-  public isAvailableSpots(): boolean {
-    if (this.slave_shapes_list && this.slave_shapes_list.items)
-      return !!Object.keys(this.filterAvailableSpots()).length;
-
-    return false;
-  }
-
-  public open(params, notebook_instance, full_list): void {
-    if (!this.bindDialog.isOpened) {
-      this.notebook_instance = notebook_instance;
-      this.full_list = full_list;
-      this.model = new ComputationalResourceCreateModel('', 0, '', '', notebook_instance.name,
-        response => {
-          if (response.status === HTTP_STATUS_CODES.OK) {
-            this.close();
-            this.buildGrid.emit();
-          }
-        },
-        error => this.toastr.error(error.message || 'Computational resource creation failed!', 'Oops!'),
-        () => this.template_description = this.model.selectedItem.description,
-        () => {
-          this.bindDialog.open(params);
-          this.bindDialog.modalClass += !this.model.availableTemplates ? 'reset' : '';
-
-          this.ref.detectChanges();
-
-          this.setDefaultParams();
-          this.getComputationalResourceLimits();
-        },
-        this.userResourceService);
-    }
-  }
-
   public preemptibleCounter($event, action): void {
     $event.preventDefault();
 
@@ -241,19 +118,33 @@
     this.resourceForm.controls.preemptible_instance_number.setValue(newValue);
   }
 
-  public close(): void {
-    if (this.bindDialog.isOpened)
-      this.bindDialog.close();
+  public isAvailableSpots(): boolean {
+    if (DICTIONARY.cloud_provider === 'aws' && this.selectedImage.image === 'docker.dlab-dataengine-service')
+      return !!Object.keys(this.filterAvailableSpots()).length;
+
+    return false;
+  }
+
+  public createComputationalResource(data) {
+    this.model.createComputationalResource(data, this.selectedImage, this.notebook_instance, this.spotInstance)
+      .subscribe((response: any) => {
+        if (response.status === HTTP_STATUS_CODES.OK) this.dialogRef.close();
+      });
   }
 
   private initFormModel(): void {
     this.resourceForm = this._fb.group({
-      cluster_alias_name: ['', [Validators.required, Validators.pattern(this.clusterNamePattern),
-                                this.providerMaxLength, this.checkDuplication.bind(this)]],
-      instance_number: ['', [Validators.required, Validators.pattern(this.nodeCountPattern), this.validInstanceNumberRange.bind(this)]],
-      preemptible_instance_number: [0, Validators.compose([Validators.pattern(this.integerRegex), this.validPreemptibleRange.bind(this)])],
+      template_name: ['', [Validators.required]],
+      version: [''],
+      shape_master: ['', Validators.required],
+      shape_slave: [''],
+      cluster_alias_name: ['', [Validators.required, Validators.pattern(PATTERNS.namePattern),
+      this.providerMaxLength, this.checkDuplication.bind(this)]],
+      instance_number: ['', [Validators.required, Validators.pattern(PATTERNS.nodeCountPattern), this.validInstanceNumberRange.bind(this)]],
+      preemptible_instance_number: [0, Validators.compose([Validators.pattern(PATTERNS.integerRegex), this.validPreemptibleRange.bind(this)])],
       instance_price: [0, [this.validInstanceSpotRange.bind(this)]],
-      configuration_parameters: ['', [this.validConfiguration.bind(this)]]
+      configuration_parameters: ['', [this.validConfiguration.bind(this)]],
+      custom_tag: [this.notebook_instance.tags.custom_tag]
     });
   }
 
@@ -262,22 +153,22 @@
   }
 
   private getComputationalResourceLimits(): void {
-    if (this.model.availableTemplates && this.model.selectedImage && this.model.selectedImage.image) {
-      const activeImage = DICTIONARY[this.model.selectedImage.image];
+    if (this.selectedImage && this.selectedImage.image) {
+      const activeImage = DICTIONARY[this.selectedImage.image];
 
-      this.minInstanceNumber = this.model.selectedImage.limits[activeImage.total_instance_number_min];
-      this.maxInstanceNumber = this.model.selectedImage.limits[activeImage.total_instance_number_max];
+      this.minInstanceNumber = this.selectedImage.limits[activeImage.total_instance_number_min];
+      this.maxInstanceNumber = this.selectedImage.limits[activeImage.total_instance_number_max];
 
-      if (DICTIONARY.cloud_provider === 'gcp' && this.model.selectedImage.image === 'docker.dlab-dataengine-service') {
-        this.maxInstanceNumber = this.model.selectedImage.limits[activeImage.total_instance_number_max] - 1;
-        this.minPreemptibleInstanceNumber = this.model.selectedImage.limits.min_dataproc_preemptible_instance_count;
+      if (DICTIONARY.cloud_provider === 'gcp' && this.selectedImage.image === 'docker.dlab-dataengine-service') {
+        this.maxInstanceNumber = this.selectedImage.limits[activeImage.total_instance_number_max] - 1;
+        this.minPreemptibleInstanceNumber = this.selectedImage.limits.min_dataproc_preemptible_instance_count;
       }
 
-      if (DICTIONARY.cloud_provider === 'aws' && this.model.selectedImage.image === 'docker.dlab-dataengine-service') {
-        this.minSpotPrice = this.model.selectedImage.limits.min_emr_spot_instance_bid_pct;
-        this.maxSpotPrice = this.model.selectedImage.limits.max_emr_spot_instance_bid_pct;
+      if (DICTIONARY.cloud_provider === 'aws' && this.selectedImage.image === 'docker.dlab-dataengine-service') {
+        this.minSpotPrice = this.selectedImage.limits.min_emr_spot_instance_bid_pct;
+        this.maxSpotPrice = this.selectedImage.limits.max_emr_spot_instance_bid_pct;
 
-        this.spotInstancesSelect.nativeElement['checked'] = true;
+        if (this.spotInstancesSelect) this.spotInstancesSelect.nativeElement['checked'] = true;
         this.selectSpotInstances();
       }
 
@@ -286,9 +177,10 @@
     }
   }
 
+  //  Validation
   private validInstanceNumberRange(control) {
     if (control && control.value)
-      if (DICTIONARY.cloud_provider === 'gcp' && this.model.selectedImage.image === 'docker.dlab-dataengine-service') {
+      if (DICTIONARY.cloud_provider === 'gcp' && this.selectedImage.image === 'docker.dlab-dataengine-service') {
         this.validPreemptibleNumberRange();
         return control.value >= this.minInstanceNumber && control.value <= this.maxInstanceNumber ? null : { valid: false };
       } else {
@@ -341,57 +233,61 @@
       return control.value.length <= 10 ? null : { valid: false };
   }
 
-  private setDefaultParams(): void {
-    if (this.model.selectedImage && this.model.selectedImage.shapes) {
-      this.filterShapes();
-      this.shapes = {
-        master_shape: this.shapePlaceholder(this.model.selectedImage.shapes.resourcesShapeTypes, 'type'),
-        slave_shape: this.shapePlaceholder(this.model.selectedImage.shapes.resourcesShapeTypes, 'type')
-      };
-      if (DICTIONARY.cloud_provider !== 'azure' && this.cluster_type) {
-        this.cluster_type.setDefaultOptions(this.model.resourceImages,
-          this.model.selectedImage.template_name, 'cluster_type', 'template_name', 'array');
-          if (this.model.selectedImage.image === 'docker.dlab-dataengine-service')
-            this.templates_list.setDefaultOptions(this.model.templates,
-              this.model.selectedItem.version, 'template', 'version', 'array');
-      }
-      this.master_shapes_list && this.master_shapes_list.setDefaultOptions(this.model.selectedImage.shapes.resourcesShapeTypes,
-        this.shapePlaceholder(this.model.selectedImage.shapes.resourcesShapeTypes, 'description'), 'master_shape', 'description', 'json');
-        this.slave_shapes_list && this.slave_shapes_list.setDefaultOptions(this.model.selectedImage.shapes.resourcesShapeTypes,
-        this.shapePlaceholder(this.model.selectedImage.shapes.resourcesShapeTypes, 'description'), 'slave_shape', 'description', 'json');
-    }
+  private getTemplates(project) {
+    this.userResourceService.getComputationalTemplates(project).subscribe(
+      clusterTypes => {
+        this.clusterTypes = clusterTypes;
+        this.selectedImage = clusterTypes[0];
+
+        if (this.selectedImage) {
+          this.getComputationalResourceLimits();
+          this.filterShapes();
+          this.resourceForm.get('template_name').setValue(this.selectedImage.template_name);
+        }
+      }, error => { });
   }
 
   private filterShapes(): void {
     if (this.notebook_instance.template_name.toLowerCase().indexOf('tensorflow') !== -1
       || this.notebook_instance.template_name.toLowerCase().indexOf('deep learning') !== -1) {
       const allowed: any = ['GPU optimized'];
-      const filtered = Object.keys(this.model.selectedImage.shapes.resourcesShapeTypes)
+      const filtered = Object.keys(this.selectedImage.computation_resources_shapes)
         .filter(key => allowed.includes(key))
         .reduce((obj, key) => {
-          obj[key] = this.model.selectedImage.shapes.resourcesShapeTypes[key];
+          obj[key] = this.selectedImage.computation_resources_shapes[key];
           return obj;
         }, {});
 
       if (DICTIONARY.cloud_provider !== 'azure') {
-        const images = this.model.resourceImages.filter(image => image.image === 'docker.dlab-dataengine');
-        this.model.resourceImages = images;
-        (images.length > 0) ? this.model.setSelectedClusterType(0) : this.model.availableTemplates = false;
+        const images = this.clusterTypes.filter(image => image.image === 'docker.dlab-dataengine');
+        this.clusterTypes = images;
       }
-      this.model.selectedImage.shapes.resourcesShapeTypes = filtered;
+      this.selectedImage.computation_resources_shapes = filtered;
     }
   }
 
-  private resetDialog(): void {
-    this.spotInstance = false;
-    this.initFormModel();
-    this.getComputationalResourceLimits();
-    this.model.resetModel();
+  private filterAvailableSpots() {
+    const filtered = JSON.parse(JSON.stringify(this.selectedImage.computation_resources_shapes));
+    for (const item in this.selectedImage.computation_resources_shapes) {
+      filtered[item] = filtered[item].filter(el => el.spot);
+      if (filtered[item].length <= 0) {
+        delete filtered[item];
+      }
+    }
+    return filtered;
+  }
 
-    if (this.PROVIDER === 'aws' && this.spotInstancesSelect)
-      this.spotInstancesSelect.nativeElement['checked'] = false;
-
-    if (this.PROVIDER === 'gcp' && this.preemptible)
-      this.preemptible.nativeElement['checked'] = false;
+  private containsComputationalResource(conputational_resource_name: string): boolean {
+    if (conputational_resource_name)
+      for (let index = 0; index < this.resourcesList.length; index++) {
+        if (this.notebook_instance.name === this.resourcesList[index].name) {
+          for (let iindex = 0; iindex < this.resourcesList[index].resources.length; iindex++) {
+            const computational_name = this.resourcesList[index].resources[iindex].computational_name.toString().toLowerCase();
+            if (CheckUtils.delimitersFiltering(conputational_resource_name) === CheckUtils.delimitersFiltering(computational_name))
+              return true;
+          }
+        }
+      }
+    return false;
   }
 }
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 d53285a..00b34d7 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
@@ -18,186 +18,64 @@
  */
 /* tslint:disable:no-empty */
 
+import { Injectable } from '@angular/core';
 import { Observable } from 'rxjs';
 
 import { UserResourceService } from '../../../core/services';
-import { ComputationalResourceImage,
-         ComputationalResourceApplicationTemplate,
-         ResourceShapeTypesModel } from '../../../core/models';
 import { DICTIONARY } from '../../../../dictionary/global.dictionary';
 
-export class ComputationalResourceCreateModel {
+@Injectable()
+export class ComputationalResourceModel {
 
-  confirmAction: Function;
-  selectedItemChanged: Function;
+  constructor(private userResourceService: UserResourceService) { }
 
-  computational_resource_alias: string;
-  computational_resource_count: number;
-  computational_resource_instance_shape: string;
-  computational_resource_slave_shape: string;
-  notebook_name: string;
-  emr_slave_instance_spot: boolean;
-  emr_slave_instance_price: number;
-  preemptible_inst: number;
-  config: any;
+  public createComputationalResource(parameters, image, env, spot): Observable<{}> {
+    const config = parameters.configuration_parameters ? JSON.parse(parameters.configuration_parameters) : null;
 
-  selectedItem: ComputationalResourceApplicationTemplate = new ComputationalResourceApplicationTemplate({},
-    new ResourceShapeTypesModel({}), '', '', '');
-  selectedImage: ComputationalResourceImage;
-  resourceImages: Array<ComputationalResourceImage> = [];
-  templates: Array<ComputationalResourceApplicationTemplate> = [];
-
-  availableTemplates: boolean = false;
-  private userResourceService: UserResourceService;
-  private continueWith: Function;
-
-  static getDefault(userResourceService): ComputationalResourceCreateModel {
-    return new ComputationalResourceCreateModel('', 0, '', '', '', () => { }, () => { }, null, null, userResourceService);
-  }
-
-  constructor(
-    computational_resource_alias: string,
-    computational_resource_count: number,
-    computational_resource_master_shape: string,
-    computational_resource_slave_shape: string,
-    notebook_name: string,
-    fnProcessResults: any,
-    fnProcessErrors: any,
-    selectedItemChanged: Function,
-    continueWith: Function,
-    userResourceService: UserResourceService
-  ) {
-    this.notebook_name = notebook_name;
-    this.userResourceService = userResourceService;
-    this.selectedItemChanged = selectedItemChanged;
-    this.continueWith = continueWith;
-    this.prepareModel(fnProcessResults, fnProcessErrors);
-    this.loadTemplates();
-  }
-
-  public setSelectedItem(item: ComputationalResourceApplicationTemplate) {
-    this.selectedItem = item;
-  }
-
-  public setCreatingParams(
-    name: string,
-    count: number,
-    instance_shape: string,
-    shape_slave: string,
-    spot: boolean,
-    price: number,
-    preemptible_inst?: number,
-    config?: any
-  ): void {
-    this.computational_resource_alias = name;
-    this.computational_resource_count = count;
-    this.computational_resource_instance_shape = instance_shape;
-    this.computational_resource_slave_shape = shape_slave;
-    this.emr_slave_instance_spot = spot;
-    this.emr_slave_instance_price = price;
-    this.preemptible_inst = preemptible_inst || 0;
-    this.config = config || null;
-  }
-
-  public loadTemplates(): void {
-    if (this.resourceImages.length === 0)
-      this.userResourceService.getComputationalResourcesTemplates()
-        .subscribe(
-        data => {
-          let computationalResourceImage;
-
-          this.availableTemplates = !!data.length;
-
-          for (let parentIndex = 0; parentIndex < data.length; parentIndex++) {
-            computationalResourceImage = new ComputationalResourceImage(data[parentIndex]);
-
-            if (DICTIONARY.cloud_provider !== 'azure')
-              this.resourceImages.push(computationalResourceImage);
-          }
-
-          if (this.resourceImages.length > 0 && DICTIONARY.cloud_provider !== 'azure') {
-            this.setSelectedClusterType(0);
-          } else if (DICTIONARY.cloud_provider === 'azure') {
-            this.selectedItem = computationalResourceImage || {};
-            this.selectedImage = computationalResourceImage || {};
-          }
-
-          if (this.continueWith)
-            this.continueWith();
-        });
-  }
-
-  public setSelectedClusterType(index) {
-    this.selectedImage = this.resourceImages[index];
-    this.templates = [];
-
-    for (let index = 0; index < this.selectedImage.application_templates.length; index++)
-      this.templates.push(this.selectedImage.application_templates[index]);
-
-    this.setSelectedTemplate(0);
-  }
-
-  public setSelectedTemplate(index: number): void {
-    if (this.templates && this.templates[index]) {
-      this.selectedItem = this.templates[index];
-      if (this.selectedItemChanged)
-        this.selectedItemChanged();
-    } else {
-      this.selectedItem = null;
-    }
-  }
-
-  public resetModel() {
-    this.setSelectedTemplate(0);
-  }
-
-  private prepareModel(fnProcessResults: any, fnProcessErrors: any): void {
-    this.confirmAction = () => this.createComputationalResource()
-      .subscribe(
-      response => fnProcessResults(response),
-      error => fnProcessErrors(error)
-      );
-  }
-
-  private createComputationalResource(): Observable<{}> {
-    if (DICTIONARY.cloud_provider === 'aws' && this.selectedImage.image === 'docker.dlab-dataengine-service') {
+    if (DICTIONARY.cloud_provider === 'aws' && image.image === 'docker.dlab-dataengine-service') {
       return this.userResourceService.createComputationalResource_DataengineService({
-        name: this.computational_resource_alias,
-        emr_instance_count: this.computational_resource_count,
-        emr_master_instance_type: this.computational_resource_instance_shape,
-        emr_slave_instance_type: this.computational_resource_slave_shape,
-        emr_version: this.selectedItem.version,
-        notebook_name: this.notebook_name,
-        image: this.selectedItem.image,
-        template_name: this.selectedItem.template_name,
-        emr_slave_instance_spot: this.emr_slave_instance_spot,
-        emr_slave_instance_spot_pct_price: this.emr_slave_instance_price,
-        config: this.config
+        name: parameters.cluster_alias_name,
+        emr_instance_count: parameters.instance_number,
+        emr_master_instance_type: parameters.shape_master,
+        emr_slave_instance_type: parameters.shape_slave,
+        emr_version: parameters.version,
+        notebook_name: env.name,
+        image: image.image,
+        template_name: image.template_name,
+        emr_slave_instance_spot: spot,
+        emr_slave_instance_spot_pct_price: parameters.emr_slave_instance_price,
+        config: config,
+        project: env.project,
+        custom_tag: parameters.custom_tag
       });
-    } else if (DICTIONARY.cloud_provider === 'gcp' && this.selectedImage.image === 'docker.dlab-dataengine-service') {
+    } else if (DICTIONARY.cloud_provider === 'gcp' && image.image === 'docker.dlab-dataengine-service') {
       return this.userResourceService.createComputationalResource_DataengineService({
-        name: this.computational_resource_alias,
-        template_name: this.selectedItem.template_name,
-        notebook_name: this.notebook_name,
-        image: this.selectedItem.image,
-        dataproc_master_instance_type:  this.computational_resource_instance_shape,
-        dataproc_slave_instance_type: this.computational_resource_slave_shape,
-        dataproc_version: this.selectedItem.version,
+        name: parameters.cluster_alias_name,
+        dataproc_slave_count: (parameters.instance_number - 1),
+        template_name: image.template_name,
+        notebook_name: env.name,
+        image: image.image,
+        dataproc_master_instance_type: parameters.shape_master,
+        dataproc_slave_instance_type: parameters.shape_slave,
+        dataproc_version: image.version,
         dataproc_master_count: 1,
-        dataproc_slave_count: (this.computational_resource_count - 1),
-        dataproc_preemptible_count: this.preemptible_inst,
-        config: this.config
+        dataproc_preemptible_count: parameters.preemptible_instance_number,
+        config: config,
+        project: env.project,
+        custom_tag: parameters.custom_tag
       });
     } else {
       return this.userResourceService.createComputationalResource_Dataengine({
-        name: this.computational_resource_alias,
-        dataengine_instance_count: this.computational_resource_count,
-        dataengine_instance_shape: this.computational_resource_instance_shape,
-        notebook_name: this.notebook_name,
-        image: this.selectedImage.image,
-        template_name: this.selectedImage.template_name,
-        config: this.config
+        name: parameters.cluster_alias_name,
+        dataengine_instance_count: parameters.instance_number,
+        dataengine_instance_shape: parameters.shape_master,
+        notebook_name: env.name,
+        image: image.image,
+        template_name: image.template_name,
+        config: config,
+        project: env.project,
+        custom_tag: parameters.custom_tag
       });
     }
-  };
+  }
 }
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 3fe3ce7..4586b9e 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
@@ -21,21 +21,25 @@
 import { CommonModule } from '@angular/common';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 
-import { ModalModule } from '../../../shared/modal-dialog';
 import { MaterialModule } from '../../../shared/material.module';
 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';
 
 @NgModule({
   imports: [
     CommonModule,
-    ModalModule,
     FormsModule,
     ReactiveFormsModule,
     FormControlsModule,
+    KeysPipeModule,
+    UnderscorelessPipeModule,
     MaterialModule
   ],
   declarations: [ComputationalResourceCreateDialogComponent],
+  providers: [ComputationalResourceModel],
+  entryComponents: [ComputationalResourceCreateDialogComponent],
   exports: [ComputationalResourceCreateDialogComponent]
 })
 export class ComputationalResourceCreateDialogModule {}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resources-list/computational-resources-list.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resources-list/computational-resources-list.component.html
index 3881705..d4cac2c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resources-list/computational-resources-list.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resources-list/computational-resources-list.component.html
@@ -34,21 +34,19 @@
         <div class="resource-actions">
           <a class="schedule" [ngClass]="{'active': resource.scheduler_data,
               'not-allowed': environment.status !== 'running' && environment.status !== 'stopped'
-              || resource.status !== 'running' && resource.status !== 'stopped'
-              || healthStatus === 'error' }">
+              || resource.status !== 'running' && resource.status !== 'stopped' }">
             <i class="material-icons" (click)="openScheduleDialog(resource)">schedule</i>
           </a>
   
           <a class="start-stop-action" *ngIf="resource.image === 'docker.dlab-dataengine' && environment.status === 'running'">
             <i class="material-icons" *ngIf="resource.status === 'running' || resource.status === 'stopping'" (click)="toggleResourceAction(resource, 'stop')"
-              [ngClass]="{'not-allowed' : resource.status === 'stopping' || healthStatus === 'error'}">pause_circle_outline</i>
+              [ngClass]="{'not-allowed' : resource.status === 'stopping' }">pause_circle_outline</i>
             <i class="material-icons" *ngIf="resource.status === 'stopped' || resource.status === 'starting'" (click)="toggleResourceAction(resource, 'start')"
-              [ngClass]="{'not-allowed' : resource.status === 'starting' || healthStatus === 'error'}">play_circle_outline</i>
+              [ngClass]="{'not-allowed' : resource.status === 'starting' }">play_circle_outline</i>
           </a>
   
           <a class="remove_butt" [ngClass]="{'disabled' : environment.status !== 'running' || environment.status !== 'stopped'
-              && resource.status != 'running' && resource.status != 'failed' && resource.status != 'stopped',
-              'not-allowed' : healthStatus === 'error'}" (click)="toggleResourceAction(resource, 'terminate')">
+              && resource.status != 'running' && resource.status != 'failed' && resource.status != 'stopped' }" (click)="toggleResourceAction(resource, 'terminate')">
             <i class="material-icons">highlight_off</i>
           </a>
         </div>
@@ -56,5 +54,5 @@
     </div>
   </div>
   
-  <dlab-cluster-details #detailComputationalResource (buildGrid)="rebuildGrid()"></dlab-cluster-details>
-  <dlab-scheduler #clusterScheduler (buildGrid)="rebuildGrid()"></dlab-scheduler>
+  <!-- <dlab-cluster-details #detailComputationalResource (buildGrid)="rebuildGrid()"></dlab-cluster-details> -->
+  <!-- <dlab-scheduler #clusterScheduler (buildGrid)="rebuildGrid()"></dlab-scheduler> -->
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resources-list/computational-resources-list.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resources-list/computational-resources-list.component.ts
index a6d08db..02ede96 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resources-list/computational-resources-list.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resources-list/computational-resources-list.component.ts
@@ -18,10 +18,12 @@
  */
 
 import { Component, EventEmitter, Input, Output, ViewChild, Inject } from '@angular/core';
+import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
 import { ToastrService } from 'ngx-toastr';
 
 import { UserResourceService } from '../../../core/services';
-import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
+import { DetailComputationalResourcesComponent } from '../cluster-details';
+import { SchedulerComponent } from '../../scheduler';
 
 @Component({
   selector: 'computational-resources-list',
@@ -36,14 +38,13 @@
 
   @Input() resources: any[];
   @Input() environment: any[];
-  @Input() healthStatus: string;
 
   @Output() buildGrid: EventEmitter<{}> = new EventEmitter();
 
   constructor(
-    private userResourceService: UserResourceService,
     public dialog: MatDialog,
-    public toastr: ToastrService
+    public toastr: ToastrService,
+    private userResourceService: UserResourceService
   ) { }
 
   toggleResourceAction(resource, action: string) {
@@ -79,11 +80,15 @@
   }
 
   detailComputationalResources(environment, resource): void {
-    this.detailComputationalResource.open({ isFooter: false }, environment, resource);
+    // this.detailComputationalResource.open({ isFooter: false }, environment, resource);
+    this.dialog.open(DetailComputationalResourcesComponent, { data: { environment, resource }, panelClass: 'modal-sm'})
+               .afterClosed().subscribe(() => this.rebuildGrid());
   };
 
   openScheduleDialog(resource) {
-    this.clusterScheduler.open({ isFooter: false }, this.environment, 'СOMPUTATIONAL', resource);
+    // this.clusterScheduler.open({ isFooter: false }, this.environment, 'СOMPUTATIONAL', resource);
+    this.dialog.open(SchedulerComponent, { data: {notebook: this.environment, type: 'СOMPUTATIONAL', resource}, panelClass: 'modal-xl-s' })
+               .afterClosed().subscribe(() => this.rebuildGrid());
   }
 }
 
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resources-list/index.ts b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resources-list/index.ts
index be798a8..abdb7dd 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resources-list/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/computational/computational-resources-list/index.ts
@@ -21,7 +21,6 @@
 import { CommonModule } from '@angular/common';
 
 import { MaterialModule } from '../../../shared/material.module';
-import { ModalModule } from '../../../shared';
 import { ComputationalResourcesListComponent, ConfirmationDialogComponent } from './computational-resources-list.component';
 import { DetailComputationalResourcesModule } from '../cluster-details';
 import { SchedulerModule } from '../../scheduler';
@@ -31,7 +30,6 @@
 @NgModule({
   imports: [
     CommonModule,
-    ModalModule,
     DetailComputationalResourcesModule,
     SchedulerModule,
     MaterialModule
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 24b979f..cc817fe 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
@@ -17,11 +17,12 @@
   ~ under the License.
   -->
 
-<modal-dialog #bindDialog modalClass="ami-dialog modal-sm">
-  <modal-header>
-    <h4 class="modal-title" id="myModalLabel">Create {{ DICTIONARY.image }}</h4>
-  </modal-header>
-  <modal-content>
+<div class="ami-dialog" id="dialog-box">
+  <header class="dialog-header">
+    <h4 class="modal-title">Create {{ DICTIONARY.image }}</h4>
+    <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+  </header>
+  <div class="dialog-content">
     <div class="content-box" *ngIf="notebook">
       <form [formGroup]="createAMIForm" novalidate>
         <div class="control-group">
@@ -43,9 +44,9 @@
         </div>
       </form>
       <div class="text-center m-top-30 m-bott-10">
-        <button mat-raised-button type="button" class="butt action" (click)="resetForm()">Cancel</button>
+        <button mat-raised-button type="button" class="butt action" (click)="dialogRef.close()">Cancel</button>
         <button mat-raised-button type="button" [disabled]="!createAMIForm.valid" (click)="assignChanges(createAMIForm.value)" class="butt butt-success action">Create</button>
       </div>
     </div>
-  </modal-content>
-</modal-dialog>
+  </div>
+</div>
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 1011f74..14abbb3 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
@@ -17,8 +17,9 @@
  * under the License.
  */
 
-import { Component, OnInit, ViewChild, Output, EventEmitter } from '@angular/core';
+import { Component, OnInit, Inject } from '@angular/core';
 import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
 import { ToastrService } from 'ngx-toastr';
 
 import { UserResourceService } from '../../../core/services';
@@ -39,41 +40,32 @@
   delimitersRegex = /[-_]?/g;
   imagesList: any;
 
-  @ViewChild('bindDialog') bindDialog;
-  @Output() buildGrid: EventEmitter<{}> = new EventEmitter();
-
   constructor(
+    @Inject(MAT_DIALOG_DATA) public data: any,
+    public toastr: ToastrService,
+    public dialogRef: MatDialogRef<AmiCreateDialogComponent>,
     private _userResource: UserResourceService,
     private _fb: FormBuilder,
-    public toastr: ToastrService
-  ) {}
+  ) { }
 
   ngOnInit() {
     this._userResource.getImagesList().subscribe(res => this.imagesList = res);
+    this.open(this.data);
   }
 
-  public open(param, notebook): void {
+  public open(notebook): void {
     this.notebook = notebook;
 
     this.initFormModel();
     this._userResource.getImagesList().subscribe(res => this.imagesList = res);
-    this.bindDialog.open(param);
-  }
-
-  public resetForm() {
-    this.initFormModel();
-    this.bindDialog.close();
   }
 
   public assignChanges(data) {
     this._userResource.createAMI(data).subscribe(
       response => {
-        if (response.status === HTTP_STATUS_CODES.ACCEPTED) {
-          this.bindDialog.close();
-          this.buildGrid.emit();
-        }
+        if (response.status === HTTP_STATUS_CODES.ACCEPTED) this.dialogRef.close();
       },
-      error => this.toastr.error(error.message || `${ DICTIONARY.image.toLocaleUpperCase() } creation failed!`, 'Oops!'));
+      error => this.toastr.error(error.message || `${DICTIONARY.image.toLocaleUpperCase()} creation failed!`, 'Oops!'));
   }
 
   private initFormModel(): void {
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/index.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/index.ts
index 1d3bfc7..bc00c97 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/index.ts
@@ -22,19 +22,18 @@
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 import { MaterialModule } from '../../../shared/material.module';
 
-import { ModalModule } from '../../../shared';
 import { AmiCreateDialogComponent } from './ami-create-dialog.component';
 export * from './ami-create-dialog.component';
 
 @NgModule({
   imports: [
     CommonModule,
-    ModalModule,
     MaterialModule,
     FormsModule,
     ReactiveFormsModule
   ],
   declarations: [AmiCreateDialogComponent],
+  entryComponents: [AmiCreateDialogComponent],
   exports: [AmiCreateDialogComponent]
 })
 export class AmiCreateDialogModule {}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/billing/cost-details-dialog/cost-details-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/cost-details-dialog/cost-details-dialog.component.html
similarity index 92%
rename from services/self-service/src/main/resources/webapp/src/app/resources/billing/cost-details-dialog/cost-details-dialog.component.html
rename to services/self-service/src/main/resources/webapp/src/app/resources/exploratory/cost-details-dialog/cost-details-dialog.component.html
index 8a370d8..700cc54 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/billing/cost-details-dialog/cost-details-dialog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/cost-details-dialog/cost-details-dialog.component.html
@@ -17,9 +17,11 @@
   ~ under the License.
   -->
 
-<modal-dialog #bindDialog modalClass="billing-detail-dialog header-white modal-xl">
-  <modal-header></modal-header>
-  <modal-content>
+<div id="dialog-box" class="billing-detail-dialog">
+  <header class="dialog-header header-white">
+    <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+  </header>
+  <div class="dialog-content">
     <div *ngIf="notebook">
       <table class="detail-header">
         <tr>
@@ -58,5 +60,5 @@
           <strong>Total: </strong>{{ notebook.cost }} {{ notebook.currency_code }}</div>
       </div>
     </div>
-  </modal-content>
-</modal-dialog>
+  </div>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/billing/cost-details-dialog/cost-details-dialog.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/cost-details-dialog/cost-details-dialog.component.scss
similarity index 100%
rename from services/self-service/src/main/resources/webapp/src/app/resources/billing/cost-details-dialog/cost-details-dialog.component.scss
rename to services/self-service/src/main/resources/webapp/src/app/resources/exploratory/cost-details-dialog/cost-details-dialog.component.scss
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/billing/cost-details-dialog/cost-details-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/cost-details-dialog/cost-details-dialog.component.ts
similarity index 65%
rename from services/self-service/src/main/resources/webapp/src/app/resources/billing/cost-details-dialog/cost-details-dialog.component.ts
rename to services/self-service/src/main/resources/webapp/src/app/resources/exploratory/cost-details-dialog/cost-details-dialog.component.ts
index 30733ba..39bb770 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/billing/cost-details-dialog/cost-details-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/cost-details-dialog/cost-details-dialog.component.ts
@@ -17,27 +17,25 @@
  * under the License.
  */
 
-import { Component, ViewChild } from '@angular/core';
+import { Component, OnInit, Inject } from '@angular/core';
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
 import { DICTIONARY } from '../../../../dictionary/global.dictionary';
 
 @Component({
-    selector: 'cost-details-dialog',
-    templateUrl: 'cost-details-dialog.component.html',
-    styleUrls: ['cost-details-dialog.component.scss']
+  selector: 'cost-details-dialog',
+  templateUrl: 'cost-details-dialog.component.html',
+  styleUrls: ['cost-details-dialog.component.scss']
 })
-export class CostDetailsDialogComponent {
+export class CostDetailsDialogComponent implements OnInit {
   readonly DICTIONARY = DICTIONARY;
   public notebook: any;
 
-  @ViewChild('bindDialog') bindDialog;
+  constructor(
+    @Inject(MAT_DIALOG_DATA) public data: any,
+    public dialogRef: MatDialogRef<CostDetailsDialogComponent>
+  ) { }
 
-  public open(params, notebook): void {
-    this.notebook = notebook;
-    this.bindDialog.open(params);
-  }
-
-  public close(): void {
-    if (this.bindDialog.isOpened)
-      this.bindDialog.close();
+  ngOnInit() {
+    this.notebook = this.data;
   }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/billing/cost-details-dialog/index.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/cost-details-dialog/index.ts
similarity index 92%
rename from services/self-service/src/main/resources/webapp/src/app/resources/billing/cost-details-dialog/index.ts
rename to services/self-service/src/main/resources/webapp/src/app/resources/exploratory/cost-details-dialog/index.ts
index 859295e..b95c183 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/billing/cost-details-dialog/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/cost-details-dialog/index.ts
@@ -22,13 +22,13 @@
 
 import { MaterialModule } from '../../../shared/material.module';
 import { CostDetailsDialogComponent } from './cost-details-dialog.component';
-import { ModalModule } from '../../../shared';
 
 export * from './cost-details-dialog.component';
 
 @NgModule({
-  imports: [CommonModule, ModalModule, MaterialModule],
+  imports: [CommonModule, MaterialModule],
   declarations: [CostDetailsDialogComponent],
+  entryComponents: [CostDetailsDialogComponent],
   exports: [CostDetailsDialogComponent]
 })
 export class CostDetailsDialogModule {}
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
new file mode 100644
index 0000000..771d325
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.html
@@ -0,0 +1,177 @@
+<!--
+  ~ 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="create-environment" id="dialog-box">
+  <header class="dialog-header">
+    <h4 class="modal-title">Create analytical tool</h4>
+    <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+  </header>
+  <div class="dialog-content selection">
+    <div class="content-box mat-reset">
+      <form [formGroup]="createExploratoryForm" *ngIf="createExploratoryForm" novalidate>
+        <div class="control-group">
+          <label class="label">Select project</label>
+          <div class="control selector-wrapper">
+            <mat-form-field>
+              <mat-label>Select project</mat-label>
+              <mat-select formControlName="project" disableOptionCentering>
+                <mat-option *ngFor="let project of projects" [value]="project.name"
+                  (click)="getTemplates($event, project)">{{ project.name }}</mat-option>
+                <mat-option *ngIf="!projects.length" class="multiple-select ml-10" disabled>Projects list is empty
+                </mat-option>
+              </mat-select>
+              <button class="caret">
+                <i class="material-icons">keyboard_arrow_down</i>
+              </button>
+            </mat-form-field>
+          </div>
+        </div>
+
+        <div class="control-group">
+          <label class="label">Select endpoint</label>
+          <div class="control selector-wrapper" [ngClass]="{ 'not-active' : !endpoints.length }">
+            <mat-form-field>
+              <mat-label>Select endpoint</mat-label>
+              <mat-select formControlName="endpoint" disableOptionCentering [disabled]="!endpoints.length">
+                <mat-option *ngFor="let endpoint of endpoints" [value]="endpoint">{{ endpoint }}</mat-option>
+                <mat-option *ngIf="!endpoints.length" class="multiple-select ml-10" disabled>Endpoints list is empty
+                </mat-option>
+              </mat-select>
+              <button class="caret">
+                <i class="material-icons">keyboard_arrow_down</i>
+              </button>
+            </mat-form-field>
+          </div>
+        </div>
+
+        <div class="control-group">
+          <label class="label">Select template</label>
+          <div class="control selector-wrapper" [ngClass]="{ 'not-active' : !templates.length }">
+            <mat-form-field>
+              <mat-label>Select template</mat-label>
+              <mat-select formControlName="version" disableOptionCentering [disabled]="!templates.length">
+                <mat-option *ngFor="let template of templates"
+                  [value]="template.exploratory_environment_versions[0].version" (click)="getShapes(template)">
+                  {{ template.exploratory_environment_versions[0].template_name }}
+                </mat-option>
+                <mat-option *ngIf="!templates.length" class="multiple-select ml-10" disabled>Templates list is empty
+                </mat-option>
+              </mat-select>
+              <button class="caret">
+                <i class="material-icons">keyboard_arrow_down</i>
+              </button>
+            </mat-form-field>
+          </div>
+        </div>
+
+        <div class="control-group" *ngIf="images && images.length > 0">
+          <label class="label">Select {{ DICTIONARY.image }}</label>
+          <div class="control selector-wrapper">
+            <mat-form-field>
+              <mat-label>Select {{ DICTIONARY.image }}</mat-label>
+              <mat-select formControlName="notebook_image_name" disableOptionCentering>
+                <mat-option [value]="null">None</mat-option>
+                <mat-option *ngFor="let image of images" [value]="image.name">{{ image.name }}</mat-option>
+                <mat-option *ngIf="!images.length" class="multiple-select ml-10" disabled>Images list is empty
+                </mat-option>
+              </mat-select>
+              <button class="caret">
+                <i class="material-icons">keyboard_arrow_down</i>
+              </button>
+            </mat-form-field>
+          </div>
+        </div>
+
+        <div class="control-group">
+          <label class="label">Name</label>
+          <div class="control">
+            <input [class.danger_field]="notebookExist || !createExploratoryForm?.controls['name'].valid
+                    && createExploratoryForm?.controls['name'].dirty
+                    && createExploratoryForm?.controls['name'].hasError('duplication')" type="text"
+              class="form-control" placeholder="Enter Name" formControlName="name">
+            <span class="error" *ngIf="createExploratoryForm?.controls['name'].hasError('duplication')">This name
+              already exists.</span>
+            <span class="error" *ngIf="!createExploratoryForm?.controls.name.valid
+                                        && createExploratoryForm?.controls['name'].dirty
+                                        && !createExploratoryForm?.controls['name'].hasError('duplication')">Name
+              <span *ngIf="DICTIONARY.cloud_provider !== 'aws'">cannot be longer than 10 characters and</span> can only
+              contain letters, numbers, hyphens and '_' but can not end with special characters
+            </span>
+          </div>
+        </div>
+
+        <div class="control-group">
+          <label class="label">{{ DICTIONARY.notebook_instance_size }}</label>
+          <div class="control selector-wrapper" [ngClass]="{ 'not-active': !currentTemplate }">
+            <mat-form-field>
+              <mat-label>Select {{ DICTIONARY.notebook_instance_size }}</mat-label>
+              <mat-select formControlName="shape" disableOptionCentering [disabled]="!currentTemplate">
+                <mat-optgroup *ngFor="let item of (shapes | keys)" [label]="item.key | underscoreless">
+                  <mat-option *ngFor="let list_item of item.value" [value]="list_item.Type">
+                    <strong class="highlight icon-label">{{ list_item.Size }}</strong> {{ list_item.Type }}
+                  </mat-option>
+                </mat-optgroup>
+              </mat-select>
+              <button class="caret">
+                <i class="material-icons">keyboard_arrow_down</i>
+              </button>
+            </mat-form-field>
+          </div>
+        </div>
+
+        <div class="control-group">
+          <label class="label">Custom tag</label>
+          <div class="control">
+            <input type="text" class="form-control" placeholder="Enter custom tag" formControlName="custom_tag">
+          </div>
+        </div>
+
+        <div *ngIf="currentTemplate">
+          <div class="checkbox-group" *ngIf="currentTemplate?.image !== 'docker.dlab-zeppelin'; else not_support">
+            <label>
+              <input #configurationNode type="checkbox" (change)="selectConfiguration()" /> Spark configurations
+            </label>
+            <div class="config-details" [ngClass]="{ show: configuration?.nativeElement['checked'] || false }">
+              <textarea formControlName="cluster_config" placeholder="Cluster configuration template, JSON"
+                data-gramm_editor="false" id="config"></textarea>
+              <span class="error"
+                *ngIf="!createExploratoryForm?.controls.cluster_config.valid && createExploratoryForm?.controls['cluster_config'].dirty">Configuration
+                parameters is not in a valid format</span>
+            </div>
+          </div>
+          <ng-template #not_support>
+            <small>Spark default configuration for Apache Zeppelin can not be changed from DLab 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.8.0/usage/interpreter/overview.html" target="_blank">official
+                documentation</a>.
+            </small>
+          </ng-template>
+        </div>
+
+        <div class="text-center m-top-30">
+          <button mat-raised-button type="button" class="butt action" (click)="dialogRef.close()">Cancel</button>
+          <button mat-raised-button type="button" class="butt butt-success action"
+            [disabled]="!createExploratoryForm?.valid"
+            (click)="createExploratoryEnvironment(createExploratoryForm.value)">Create</button>
+        </div>
+      </form>
+    </div>
+  </div>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/exploratory-environment-create-dialog/create-environment.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.scss
similarity index 89%
rename from services/self-service/src/main/resources/webapp/src/app/resources/exploratory/exploratory-environment-create-dialog/create-environment.component.scss
rename to services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.scss
index 2eb2014..c63436c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/exploratory-environment-create-dialog/create-environment.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.scss
@@ -47,3 +47,16 @@
     }
   }
 }
+
+.control-group {
+  .error {
+    position: absolute;
+    right: 0;
+    bottom: 3px;
+  }
+}
+
+.content-box {
+  max-height: 560px;
+  overflow-y: auto;
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..6fc0b07
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.ts
@@ -0,0 +1,143 @@
+/*
+ * 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, ViewChild, Inject } from '@angular/core';
+import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
+import { ToastrService } from 'ngx-toastr';
+
+import { Project } from '../../../administration/project/project.component';
+import { UserResourceService, ProjectService } from '../../../core/services';
+import { CheckUtils, HTTP_STATUS_CODES, PATTERNS } from '../../../core/util';
+import { DICTIONARY } from '../../../../dictionary/global.dictionary';
+import { CLUSTER_CONFIGURATION } from '../../computational/computational-resource-create-dialog/cluster-configuration-templates';
+
+@Component({
+  selector: 'create-environment',
+  templateUrl: 'create-environment.component.html',
+  styleUrls: ['./create-environment.component.scss']
+})
+
+export class ExploratoryEnvironmentCreateComponent implements OnInit {
+  readonly DICTIONARY = DICTIONARY;
+  public createExploratoryForm: FormGroup;
+
+  projects: Project[] = [];
+  templates = [];
+  endpoints: Array<String> = [];
+  currentTemplate: any;
+  shapes: Array<any> = [];
+  resourceGrid: any;
+  images: Array<any>;
+
+  @ViewChild('configurationNode') configuration;
+
+  constructor(
+    @Inject(MAT_DIALOG_DATA) public data: any,
+    public toastr: ToastrService,
+    public dialogRef: MatDialogRef<ExploratoryEnvironmentCreateComponent>,
+    private userResourceService: UserResourceService,
+    private _fb: FormBuilder,
+    private projectService: ProjectService
+  ) {
+    this.resourceGrid = data;
+  }
+
+  ngOnInit() {
+    this.getUserProjects();
+    this.initFormModel();
+  }
+
+  public getProjects() {
+    this.projectService.getProjectsList().subscribe((projects: any) => this.projects = projects);
+  }
+
+  public getUserProjects() {
+    this.projectService.getUserProjectsList().subscribe((projects: any) => this.projects = projects);
+  }
+
+  public getTemplates($event, project) {
+    this.endpoints = project.endpoints;
+    this.userResourceService.getExploratoryTemplates($event.value).subscribe(templates => this.templates = templates);
+  }
+
+  public getShapes(template) {
+    this.currentTemplate = template;
+    this.shapes = template.exploratory_environment_shapes;
+    this.getImagesList();
+  }
+
+  public createExploratoryEnvironment(data) {
+    const parameters: any = {
+      image: this.currentTemplate.image,
+      template_name: this.currentTemplate.exploratory_environment_versions[0].template_name
+    };
+
+    data.cluster_config = data.cluster_config ? JSON.parse(data.cluster_config) : null
+    this.userResourceService.createExploratoryEnvironment({ ...parameters, ...data }).subscribe((response: any) => {
+      if (response.status === HTTP_STATUS_CODES.OK) this.dialogRef.close();
+    }, error => this.toastr.error(error.message || 'Exploratory creation failed!', 'Oops!'));
+  }
+
+
+  public selectConfiguration() {
+    const value = (this.configuration.nativeElement.checked && this.createExploratoryForm)
+      ? JSON.stringify(CLUSTER_CONFIGURATION.SPARK, undefined, 2) : '';
+
+    document.querySelector('#config').scrollIntoView({ block: 'start', behavior: 'smooth' });
+    this.createExploratoryForm.controls['cluster_config'].setValue(value);
+  }
+
+  private initFormModel(): void {
+
+    this.createExploratoryForm = this._fb.group({
+      project: ['', Validators.required],
+      endpoint: ['', Validators.required],
+      version: ['', Validators.required],
+      notebook_image_name: [''],
+      shape: ['', Validators.required],
+      name: ['', [Validators.required, Validators.pattern(PATTERNS.namePattern), this.providerMaxLength, this.checkDuplication.bind(this)]],
+      cluster_config: ['', [this.validConfiguration.bind(this)]],
+      custom_tag: ['', [Validators.pattern(PATTERNS.namePattern)]]
+    });
+  }
+
+  private getImagesList() {
+    this.userResourceService.getUserImages(this.currentTemplate.image)
+      .subscribe((res: any) => this.images = res.filter(el => el.status === 'CREATED'),
+        error => this.toastr.error(error.message || 'Images list loading failed!', 'Oops!'));
+  }
+
+  private checkDuplication(control) {
+    if (this.resourceGrid.containsNotebook(control.value))
+      return { duplication: true };
+  }
+
+  private providerMaxLength(control) {
+    if (DICTIONARY.cloud_provider !== 'aws')
+      return control.value.length <= 10 ? null : { valid: false };
+  }
+
+  private validConfiguration(control) {
+    if (this.configuration)
+      return this.configuration.nativeElement['checked']
+        ? (control.value && control.value !== null && CheckUtils.isJSON(control.value) ? null : { valid: false })
+        : null;
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/exploratory-environment-create-dialog/index.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/index.ts
similarity index 70%
rename from services/self-service/src/main/resources/webapp/src/app/resources/exploratory/exploratory-environment-create-dialog/index.ts
rename to services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/index.ts
index 5bed5dc..9175d9c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/exploratory-environment-create-dialog/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/index.ts
@@ -22,20 +22,24 @@
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 
 import { MaterialModule } from '../../../shared/material.module';
-import { ModalModule } from '../../../shared';
 import { FormControlsModule } from '../../../shared/form-controls';
-import { ExploratoryEnvironmentCreateDialogComponent } from './exploratory-environment-create-dialog.component';
+import { ExploratoryEnvironmentCreateComponent } from './create-environment.component';
+import { KeysPipeModule, UnderscorelessPipeModule } from '../../../core/pipes';
+
+export * from './create-environment.component';
 
 @NgModule({
   imports: [
     CommonModule,
-    ModalModule,
     FormsModule,
     ReactiveFormsModule,
     FormControlsModule,
-    MaterialModule
+    MaterialModule,
+    KeysPipeModule,
+    UnderscorelessPipeModule
   ],
-  declarations: [ExploratoryEnvironmentCreateDialogComponent],
-  exports: [ExploratoryEnvironmentCreateDialogComponent]
+  declarations: [ExploratoryEnvironmentCreateComponent],
+  entryComponents: [ExploratoryEnvironmentCreateComponent],
+  exports: [ExploratoryEnvironmentCreateComponent]
 })
-export class ExploratoryEnvironmentCreateDialogModule {}
+export class ExploratoryEnvironmentCreateModule { }
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 4fe8794..d514787 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
@@ -17,10 +17,12 @@
   ~ under the License.
   -->
 
-<modal-dialog #bindDialog modalClass="detail-dialog modal-lg header-white">
-  <modal-header></modal-header>
-  <modal-content>
-    <div *ngIf="notebook">
+<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 class="dialog-content">
+    <div *ngIf="data">
       <table class="detail-header">
         <tr>
           <td>{{notebook.template_name}}</td>
@@ -39,7 +41,7 @@
 
         <div class="scroll-box" id="scrolling">
           <div class="detail-info" *ngIf="!notebook.error_message">
-            <p>Edge Node IP Address {{notebook.ip}}</p>
+            <p>Edge Node IP Address {{notebook.node_ip}}</p>
             <p *ngIf="notebook.status === 'running'">Up time {{upTimeInHours}} hour(s) since
               {{upTimeSince || "not specified."}}</p>
             <p>Open following URL(s) in your browser to access this box:</p>
@@ -120,5 +122,5 @@
         </div>
       </div>
     </div>
-  </modal-content>
-</modal-dialog>
\ No newline at end of file
+  </div>
+</div>
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 31be5e7..81bffe3 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
@@ -17,9 +17,10 @@
  * under the License.
  */
 
-import { Component, ViewChild, OnInit, Output, EventEmitter } from '@angular/core';
+import { Component, ViewChild, OnInit, Inject } from '@angular/core';
 import { FormGroup, FormBuilder } from '@angular/forms';
 import { ToastrService } from 'ngx-toastr';
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
 
 import { DateUtils, CheckUtils } from '../../../core/util';
 import { DICTIONARY } from '../../../../dictionary/global.dictionary';
@@ -34,7 +35,6 @@
 
 export class DetailDialogComponent implements OnInit {
   readonly DICTIONARY = DICTIONARY;
-
   notebook: any;
   upTimeInHours: number;
   upTimeSince: string = '';
@@ -43,31 +43,29 @@
 
   public configurationForm: FormGroup;
 
-  @ViewChild('bindDialog') bindDialog;
   @ViewChild('configurationNode') configuration;
 
-  @Output() buildGrid: EventEmitter<{}> = new EventEmitter();
-
   constructor(
+    @Inject(MAT_DIALOG_DATA) public data: any,
     private dataengineConfigurationService: DataengineConfigurationService,
     private _fb: FormBuilder,
+    public dialogRef: MatDialogRef<DetailDialogComponent>,
     public toastr: ToastrService
-  ) {}
-
-  ngOnInit() {
-    this.bindDialog.onClosing = () => this.resetDialog();
+  ) {
+    this.notebook = data;
   }
 
-  public open(param, notebook): void {
-    this.tooltip = false;
-    this.notebook = notebook;
+  ngOnInit() {
+    this.notebook;
 
-    this.upTimeInHours = (notebook.time) ? DateUtils.diffBetweenDatesInHours(this.notebook.time) : 0;
-    this.upTimeSince = (notebook.time) ? new Date(this.notebook.time).toString() : '';
-
-    this.initFormModel();
-    this.getClusterConfiguration();
-    this.bindDialog.open(param);
+    if (this.notebook) {
+      this.tooltip = false;
+  
+      this.upTimeInHours = (this.notebook.time) ? DateUtils.diffBetweenDatesInHours(this.notebook.time) : 0;
+      this.upTimeSince = (this.notebook.time) ? new Date(this.notebook.time).toString() : '';
+      this.initFormModel();
+      this.getClusterConfiguration();
+    }
   }
 
   public isEllipsisActive($event): void {
@@ -98,8 +96,7 @@
     this.dataengineConfigurationService
       .editExploratorySparkConfiguration(data.configuration_parameters, this.notebook.name)
       .subscribe(result => {
-        this.bindDialog.close();
-        this.buildGrid.emit();
+        this.dialogRef.close();
       },
       error => this.toastr.error(error.message || 'Edit onfiguration failed!', 'Oops!'));
   }
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 1571d71..f46a7e5 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
@@ -20,7 +20,6 @@
 import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
-import { ModalModule } from '../../../shared';
 import { MaterialModule } from '../../../shared/material.module';
 import { DetailDialogComponent } from './detail-dialog.component';
 import { DirectivesModule } from '../../../core/directives';
@@ -30,13 +29,13 @@
 @NgModule({
   imports: [
     CommonModule,
-    ModalModule,
     FormsModule,
     ReactiveFormsModule,
     MaterialModule,
     DirectivesModule
   ],
   declarations: [DetailDialogComponent],
+  entryComponents: [DetailDialogComponent],
   exports: [DetailDialogComponent]
 })
 export class DetailDialogModule {}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/exploratory-environment-create-dialog/exploratory-environment-create-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/exploratory-environment-create-dialog/exploratory-environment-create-dialog.component.html
deleted file mode 100644
index 1c02d73..0000000
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/exploratory-environment-create-dialog/exploratory-environment-create-dialog.component.html
+++ /dev/null
@@ -1,93 +0,0 @@
-<!--
-  ~ 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-dialog #bindDialog modalClass="modal-lg">
-  <modal-header>
-    <h4 class="modal-title" id="myModalLabel">Create analytical tool</h4>
-  </modal-header>
-  <modal-content>
-    <div class="content-box">
-      <form [formGroup]="createExploratoryEnvironmentForm"
-            (submit)="createExploratoryEnvironment_btnClick($event, createExploratoryEnvironmentForm.value)"
-            *ngIf="createExploratoryEnvironmentForm" novalidate>
-        <div class="control-group">
-          <label class="label">Select template</label>
-          <div class="control">
-            <dropdown-list #templatesList (selectedItem)="onUpdate($event)"></dropdown-list>
-          </div>
-          <div *ngIf="model.exploratoryEnvironmentTemplates" class="mt-5">
-            <small *ngIf="model.exploratoryEnvironmentTemplates && model.exploratoryEnvironmentTemplates.length > 0 && !templateDescription">
-              {{ model.exploratoryEnvironmentTemplates[0].description }}
-            </small>
-            <small *ngIf="templateDescription">{{ templateDescription }}</small>
-          </div>
-        </div>
-
-        <div class="control-group" *ngIf="userImages && userImages.length > 0">
-          <label class="label">Select {{ DICTIONARY.image }}</label>
-          <div class="control">
-            <dropdown-list #imagesList (selectedItem)="selectImage($event)"></dropdown-list>
-          </div>
-        </div>
-
-        <div class="control-group">
-          <label class="label">Name</label>
-          <div class="control">
-            <input [class.danger_field]="notebookExist || !createExploratoryEnvironmentForm?.controls['environment_name'].valid
-                   && createExploratoryEnvironmentForm?.controls['environment_name'].dirty
-                   && createExploratoryEnvironmentForm?.controls['environment_name'].hasError('duplication')" type="text"
-                  class="form-control" placeholder="Enter Name" formControlName="environment_name">
-            <span class="danger_color" *ngIf="createExploratoryEnvironmentForm?.controls['environment_name'].hasError('duplication')">This name already exists.</span>
-            <span class="danger_color" *ngIf="!createExploratoryEnvironmentForm?.controls.environment_name.valid
-                                       && createExploratoryEnvironmentForm?.controls['environment_name'].dirty
-                                       && !createExploratoryEnvironmentForm?.controls['environment_name'].hasError('duplication')">Name
-              <span *ngIf="DICTIONARY.cloud_provider !== 'aws'">cannot be longer than 10 characters and</span> can only contain letters, numbers, hyphens and '_' but can not end with special characters
-            </span>
-          </div>
-        </div>
-        <div class="control-group">
-          <label class="label">{{ DICTIONARY.notebook_instance_size }}</label>
-          <div class="control">
-            <dropdown-list #shapesList (selectedItem)="onUpdate($event)"></dropdown-list>
-          </div>
-        </div>
-
-        <div class="checkbox-group" *ngIf="model.selectedItem.image !== 'docker.dlab-zeppelin'; else not_support">
-          <label>
-            <input #configurationNode type="checkbox" (change)="selectConfiguration()" /> Spark configurations
-          </label>
-          <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="!createExploratoryEnvironmentForm?.controls.configuration_parameters.valid && createExploratoryEnvironmentForm?.controls['configuration_parameters'].dirty">Configuration parameters is not in a valid format</span>
-          </div>
-        </div>
-        <ng-template #not_support>
-          <small>Spark default configuration for Apache Zeppelin can not be changed from DLab 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.8.0/usage/interpreter/overview.html" target="_blank">official documentation</a>.
-          </small>
-        </ng-template>
-        
-        <div class="text-center m-top-30">
-          <button mat-raised-button type="button" class="butt action" (click)="close()">Cancel</button>
-          <button mat-raised-button type="submit" [disabled]="!createExploratoryEnvironmentForm?.valid || !this.environment_shape" class="butt butt-success action">Create</button>
-        </div>
-      </form>
-    </div>
-  </modal-content>
-</modal-dialog>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/exploratory-environment-create-dialog/exploratory-environment-create-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/exploratory-environment-create-dialog/exploratory-environment-create-dialog.component.ts
deleted file mode 100644
index 365da5e..0000000
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/exploratory-environment-create-dialog/exploratory-environment-create-dialog.component.ts
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * 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, EventEmitter, Output, ViewChild, ChangeDetectorRef } from '@angular/core';
-import { FormGroup, FormBuilder, Validators } from '@angular/forms';
-import { ToastrService } from 'ngx-toastr';
-
-import { ExploratoryEnvironmentCreateModel } from './exploratory-environment-create.model';
-import { UserResourceService } from '../../../core/services';
-import { CheckUtils, HTTP_STATUS_CODES } from '../../../core/util';
-import { DICTIONARY } from '../../../../dictionary/global.dictionary';
-import { CLUSTER_CONFIGURATION } from '../../computational/computational-resource-create-dialog/cluster-configuration-templates';
-
-@Component({
-  selector: 'exploratory-environment-create-dialog',
-  templateUrl: 'exploratory-environment-create-dialog.component.html',
-  styleUrls: ['./create-environment.component.scss']
-})
-
-export class ExploratoryEnvironmentCreateDialogComponent implements OnInit {
-  readonly DICTIONARY = DICTIONARY;
-
-  model: ExploratoryEnvironmentCreateModel;
-  templateDescription: string;
-  namePattern = '[-_a-zA-Z0-9]*[_-]*[a-zA-Z0-9]+';
-  resourceGrid: any;
-  userImages: Array<any>;
-  environment_shape: string;
-
-  public createExploratoryEnvironmentForm: FormGroup;
-
-  @ViewChild('bindDialog') bindDialog;
-  @ViewChild('environment_name') environment_name;
-  @ViewChild('templatesList') templates_list;
-  @ViewChild('shapesList') shapes_list;
-  @ViewChild('imagesList') userImagesList;
-  @ViewChild('configurationNode') configuration;
-
-  @Output() buildGrid: EventEmitter<{}> = new EventEmitter();
-
-  constructor(
-    private userResourceService: UserResourceService,
-    private _fb: FormBuilder,
-    private changeDetector: ChangeDetectorRef,
-    public toastr: ToastrService
-  ) {
-    this.model = ExploratoryEnvironmentCreateModel.getDefault(userResourceService);
-  }
-
-  ngOnInit() {
-    this.initFormModel();
-    this.bindDialog.onClosing = () => this.resetDialog();
-  }
-
-  initFormModel(): void {
-    this.createExploratoryEnvironmentForm = this._fb.group({
-      environment_name: ['', [Validators.required, Validators.pattern(this.namePattern),
-                              this.providerMaxLength, this.checkDuplication.bind(this)]],
-      configuration_parameters: ['', [this.validConfiguration.bind(this)]]
-    });
-  }
-
-  providerMaxLength(control) {
-    if (DICTIONARY.cloud_provider !== 'aws')
-      return control.value.length <= 10 ? null : { valid: false };
-  }
-
-  private validConfiguration(control) {
-    if (this.configuration)
-      return this.configuration.nativeElement['checked']
-        ? (control.value && control.value !== null && CheckUtils.isJSON(control.value) ? null : { valid: false })
-        : null;
-  }
-
-  checkDuplication(control) {
-    if (this.resourceGrid.containsNotebook(control.value))
-      return { duplication: true };
-  }
-
-  shapePlaceholder(resourceShapes, byField: string): string {
-    for (const index in resourceShapes)
-      return resourceShapes[index][0][byField];
-  }
-
-  setDefaultParams(): void {
-    this.environment_shape = this.shapePlaceholder(this.model.selectedItem.shapes.resourcesShapeTypes, 'type');
-
-    this.templates_list.setDefaultOptions(this.model.exploratoryEnvironmentTemplates,
-      this.model.selectedItem.template_name, 'template', 'template_name', 'array');
-    this.shapes_list.setDefaultOptions(this.model.selectedItem.shapes.resourcesShapeTypes,
-      this.shapePlaceholder(this.model.selectedItem.shapes.resourcesShapeTypes, 'description'), 'shape', 'description', 'json');
-
-    if (this.userImages && this.userImages.length > 0) {
-      this.userImagesList.setDefaultOptions(this.userImages, 'Select existing ' + DICTIONARY.image, 'ami', 'name', 'array', null, true);
-    }
-  }
-
-  onUpdate($event): void {
-    if ($event.model.type === 'template') {
-      this.model.setSelectedTemplate($event.model.index);
-      this.shapes_list.setDefaultOptions(this.model.selectedItem.shapes.resourcesShapeTypes,
-        this.shapePlaceholder(this.model.selectedItem.shapes.resourcesShapeTypes, 'description'), 'shape', 'description', 'json');
-      this.environment_shape = this.shapePlaceholder(this.model.selectedItem.shapes.resourcesShapeTypes, 'type');
-
-      this.getImagesList();
-    }
-
-    if ($event.model.type === 'shape')
-      this.environment_shape = $event.model.value.type;
-  }
-
-  selectImage($event): void {
-    this.model.notebookImage = $event.model.value ? $event.model.value.fullName : null;
-  }
-
-  createExploratoryEnvironment_btnClick($event, data) {
-    this.model.setCreatingParams(
-      data.environment_name,
-      this.environment_shape,
-      data.configuration_parameters ? JSON.parse(data.configuration_parameters) : null);
-    this.model.confirmAction();
-    $event.preventDefault();
-    return false;
-  }
-
-  public open(params): void {
-    if (!this.bindDialog.isOpened) {
-      this.model = new ExploratoryEnvironmentCreateModel('', '', '', '', '',
-      response => {
-        if (response.status === HTTP_STATUS_CODES.OK) {
-          this.close();
-          this.buildGrid.emit();
-        }
-      },
-      error => this.toastr.error(error.message || 'Exploratory creation failed!', 'Oops!'),
-      () => this.templateDescription = this.model.selectedItem.description,
-      () => {
-        this.initFormModel();
-        this.bindDialog.open(params);
-        this.setDefaultParams();
-        this.getImagesList();
-      },
-      this.userResourceService);
-    }
-  }
-
-  getImagesList() {
-    const image = this.model.selectedItem.image;
-    this.userResourceService.getUserImages(image)
-      .subscribe((res: any) => {
-        this.userImages = res.filter(el => el.status === 'CREATED');
-
-        this.changeDetector.detectChanges();
-        this.setDefaultParams();
-      },
-      error => this.toastr.error(error.message || 'Images list loading failed!', 'Oops!'));
-  }
-
-  public selectConfiguration() {
-    if (this.configuration.nativeElement.checked && this.createExploratoryEnvironmentForm) {
-      this.createExploratoryEnvironmentForm.controls['configuration_parameters']
-        .setValue(JSON.stringify(CLUSTER_CONFIGURATION.SPARK, undefined, 2));
-    } else {
-      this.createExploratoryEnvironmentForm.controls['configuration_parameters'].setValue('');
-    }
-  }
-
-  public close(): void {
-    if (this.bindDialog.isOpened)
-      this.bindDialog.close();
-  }
-
-  private resetDialog(): void {
-    this.initFormModel();
-    this.model.resetModel();
-
-    if (this.configuration) this.configuration.nativeElement['checked'] = false;
-  }
-}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/exploratory-environment-create-dialog/exploratory-environment-create.model.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/exploratory-environment-create-dialog/exploratory-environment-create.model.ts
deleted file mode 100644
index 39430b5..0000000
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/exploratory-environment-create-dialog/exploratory-environment-create.model.ts
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * 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.
- */
-/* tslint:disable:no-empty */
-
-import { Observable } from 'rxjs';
-import { Response } from '@angular/http';
-
-import { ExploratoryEnvironmentVersionModel, ResourceShapeTypesModel } from '../../../core/models';
-import { UserResourceService } from '../../../core/services';
-import { SortUtil } from '../../../core/util';
-
-export class ExploratoryEnvironmentCreateModel {
-
-  confirmAction: Function;
-  selectedItemChanged: Function;
-
-  selectedItem: ExploratoryEnvironmentVersionModel = new ExploratoryEnvironmentVersionModel('', {}, new ResourceShapeTypesModel({}));
-  exploratoryEnvironmentTemplates: Array<ExploratoryEnvironmentVersionModel> = [];
-
-  public notebookImage: any;
-  private environment_image: string;
-  private environment_name: string;
-  private environment_template_name: string;
-  private environment_version: string;
-  private environment_shape: string;
-  private config: any;
-  private userResourceService: UserResourceService;
-  private continueWith: Function;
-
-  static getDefault(userResourceService): ExploratoryEnvironmentCreateModel {
-    return new ExploratoryEnvironmentCreateModel('', '', '', '', '', () => { }, () => { }, null, null, userResourceService);
-  }
-
-  constructor(
-    environment_image: string,
-    environment_name: string,
-    environment_template_name: string,
-    environment_version: string,
-    environment_shape: string,
-    fnProcessResults: any,
-    fnProcessErrors: any,
-    selectedItemChanged: Function,
-    continueWith: Function,
-    userResourceService: UserResourceService
-  ) {
-    this.userResourceService = userResourceService;
-    this.selectedItemChanged = selectedItemChanged;
-    this.continueWith = continueWith;
-    this.prepareModel(
-      environment_image,
-      environment_name,
-      environment_template_name,
-      environment_version,
-      environment_shape,
-      fnProcessResults,
-      fnProcessErrors);
-    this.loadTemplates();
-  }
-
-  public setSelectedItem(item: ExploratoryEnvironmentVersionModel): void {
-    this.selectedItem = item;
-  }
-
-  public setSelectedTemplate(index): void {
-    if (this.exploratoryEnvironmentTemplates && this.exploratoryEnvironmentTemplates[index]) {
-      this.selectedItem = this.exploratoryEnvironmentTemplates[index];
-      if (this.selectedItemChanged)
-        this.selectedItemChanged();
-    }
-  }
-
-  public setCreatingParams(name, shape, config?): void {
-    this.environment_image = this.selectedItem.image;
-    this.environment_version = this.selectedItem.version;
-    this.environment_template_name = this.selectedItem.template_name;
-    this.environment_name = name;
-    this.environment_shape = shape;
-    this.config = config;
-  }
-
-  public loadTemplates(): void {
-    if (this.exploratoryEnvironmentTemplates.length === 0)
-      this.userResourceService.getExploratoryEnvironmentTemplates()
-        .subscribe(
-        data => {
-          for (let parentIndex = 0; parentIndex < data.length; parentIndex++) {
-
-            const shapeJson = data[parentIndex].exploratory_environment_shapes;
-            const exploratoryJson = data[parentIndex].exploratory_environment_versions;
-            const shapeObj: ResourceShapeTypesModel = new ResourceShapeTypesModel(SortUtil.shapesSort(shapeJson));
-
-            for (let index = 0; index < exploratoryJson.length; index++)
-              this.exploratoryEnvironmentTemplates.push(
-                new ExploratoryEnvironmentVersionModel(data[parentIndex].image, exploratoryJson[index], shapeObj));
-          }
-          if (this.exploratoryEnvironmentTemplates.length > 0) {
-            this.exploratoryEnvironmentTemplates.sort(function(t1, t2) {
-              return ((t1.template_name < t2.template_name) ? -1 : ((t1.template_name > t2.template_name) ? 1 : 0));
-            });
-            this.setSelectedTemplate(0);
-          }
-
-          if (this.continueWith)
-            this.continueWith();
-        });
-  }
-
-  public resetModel(): void {
-    this.setSelectedTemplate(0);
-  }
-
-  private createExploratoryEnvironment(): Observable<{}> {
-    const params: any = {
-      image: this.environment_image,
-      template_name: this.environment_template_name,
-      name: this.environment_name,
-      shape: this.environment_shape,
-      version: this.environment_version
-    };
-    if (this.notebookImage)
-      params.notebook_image_name = this.notebookImage;
-
-    if (this.config) params.cluster_config = this.config;
-    return this.userResourceService.createExploratoryEnvironment(params);
-  }
-
-  private prepareModel(
-    environment_image: string,
-    environment_name: string,
-    environment_template_name: string,
-    environment_version: string,
-    environment_shape: string,
-    fnProcessResults: any, fnProcessErrors: any): void {
-
-    this.setCreatingParams(environment_name, environment_shape, this.config);
-    this.confirmAction = () => this.createExploratoryEnvironment()
-      .subscribe(
-        response => fnProcessResults(response),
-        error => fnProcessErrors(error));
-  }
-}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/index.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/index.ts
index 18e0ec9..526aab4 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/index.ts
@@ -22,18 +22,18 @@
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 
 import { MaterialModule } from '../../../shared/material.module';
-import { ModalModule, BubbleModule } from '../../../shared';
+import { BubbleModule } from '../../../shared';
 import { FormControlsModule } from '../../../shared/form-controls';
 
 import { KeysPipeModule, LibSortPipeModule, HighLightPipeModule } from '../../../core/pipes';
 import { InstallLibrariesComponent, ErrorMessageDialogComponent } from './install-libraries.component';
+export * from './install-libraries.component';
 
 @NgModule({
   imports: [
     CommonModule,
     FormsModule,
     ReactiveFormsModule,
-    ModalModule,
     KeysPipeModule,
     LibSortPipeModule,
     HighLightPipeModule,
@@ -42,7 +42,7 @@
     BubbleModule
   ],
   declarations: [InstallLibrariesComponent, ErrorMessageDialogComponent],
-  entryComponents: [ErrorMessageDialogComponent],
+  entryComponents: [InstallLibrariesComponent, ErrorMessageDialogComponent],
   exports: [InstallLibrariesComponent]
 })
 export class InstallLibrariesModule {}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.html
index f2d6c89..b015ab8 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.html
@@ -17,12 +17,12 @@
   ~ under the License.
   -->
 
-<modal-dialog #bindDialog modalClass="install-libraries modal-xl">
-  <modal-header>
-    <h4 class="modal-title" id="myModalLabel">Manage
-      <b>{{ notebook?.name }}</b> Libraries</h4>
-  </modal-header>
-  <modal-content>
+<div class="install-libraries" id="dialog-box">
+  <header class="dialog-header">
+    <h4 class="modal-title">Manage <b>{{ notebook?.name }}</b> Libraries</h4>
+    <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+  </header>
+  <div class="dialog-content">
    <div class="aligner">
     <div class="info" *ngIf="notebook?.status !== 'running'">
       <p class=" message">Cannot install libraries: Exploratory
@@ -151,9 +151,9 @@
       </mat-list>
     </div>
     <div class="m-top-15 actions" *ngIf="!uploading && notebook?.status === 'running'">
-      <button mat-raised-button type="button" class="butt action" (click)="close()">Close</button>
+      <button mat-raised-button type="button" class="butt action" (click)="dialogRef.close()">Close</button>
       <button mat-raised-button type="submit" class="butt butt-success action" (click)="model.confirmAction()" [disabled]="!model.selectedLibs.length || installingInProgress || !destination">Install</button>
     </div>
    </div>
-  </modal-content>
-</modal-dialog>
+  </div>
+</div>
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 a5cb02f..a41e691 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
@@ -18,26 +18,17 @@
  */
 
 
-import {debounceTime} from 'rxjs/operators';
-import { Component,
-  OnInit,
-  ViewChild,
-  Output,
-  EventEmitter,
-  ViewEncapsulation,
-  ChangeDetectorRef,
-  Inject } from '@angular/core';
+import { Component, OnInit, ViewChild, ViewEncapsulation, ChangeDetectorRef, Inject } from '@angular/core';
 import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
 import { FormControl } from '@angular/forms';
 import { ToastrService } from 'ngx-toastr';
+import { debounceTime } from 'rxjs/operators';
 
 import { InstallLibrariesModel } from './install-libraries.model';
 import { LibrariesInstallationService} from '../../../core/services';
 import { SortUtil, HTTP_STATUS_CODES } from '../../../core/util';
 
 
-
-
 @Component({
   selector: 'install-libraries',
   templateUrl: './install-libraries.component.html',
@@ -77,17 +68,16 @@
   private clear: number;
   private clearCheckInstalling = undefined;
 
-  @ViewChild('bindDialog') bindDialog;
   @ViewChild('groupSelect') group_select;
   @ViewChild('resourceSelect') resource_select;
 
-  @Output() buildGrid: EventEmitter<{}> = new EventEmitter();
-
   constructor(
+    @Inject(MAT_DIALOG_DATA) public data: any,
+    public toastr: ToastrService,
     public dialog: MatDialog,
+    public dialogRef: MatDialogRef<InstallLibrariesComponent>,
     private librariesInstallationService: LibrariesInstallationService,
-    private changeDetector: ChangeDetectorRef,
-    public toastr: ToastrService
+    private changeDetector: ChangeDetectorRef
   ) {
     this.model = InstallLibrariesModel.getDefault(librariesInstallationService);
   }
@@ -100,10 +90,7 @@
         this.query = newValue || '';
         this.filterList();
       });
-    this.bindDialog.onClosing = () => {
-      this.resetDialog();
-      this.buildGrid.emit();
-    };
+    this.open(this.data);
   }
 
   uploadLibGroups(): void {
@@ -196,33 +183,22 @@
     this.model.selectedLibs.splice(this.model.selectedLibs.indexOf(item), 1);
   }
 
-  public open(param, notebook): void {
-    if (!this.bindDialog.isOpened)
-      this.notebook = notebook;
-      this.model = new InstallLibrariesModel(notebook,
-        response => {
-          if (response.status === HTTP_STATUS_CODES.OK) {
-            this.getInstalledLibrariesList();
-            this.resetDialog();
-          }
-        },
-        error => this.toastr.error(error.message || 'Library installation failed!', 'Oops!'),
-        () => {
-          this.bindDialog.open(param);
-
-          this.getInstalledLibrariesList(true);
-          this.changeDetector.detectChanges();
-          this.selectorsReset();
-        },
-       this.librariesInstallationService);
-  }
-
-  public close(): void {
-    if (this.bindDialog.isOpened)
-      this.bindDialog.close();
-
-    this.buildGrid.emit();
-    this.resetDialog();
+  public open(notebook): void {
+    this.notebook = notebook;
+    this.model = new InstallLibrariesModel(notebook,
+      response => {
+        if (response.status === HTTP_STATUS_CODES.OK) {
+          this.getInstalledLibrariesList();
+          this.resetDialog();
+        }
+      },
+      error => this.toastr.error(error.message || 'Library installation failed!', 'Oops!'),
+      () => {
+        this.getInstalledLibrariesList(true);
+        this.changeDetector.detectChanges();
+        this.selectorsReset();
+      },
+      this.librariesInstallationService);
   }
 
   public showErrorMessage(item): void {
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/manage-ungit/manage-ungit.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/manage-ungit/manage-ungit.component.html
index c1d1e2c..6697e68 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/manage-ungit/manage-ungit.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/manage-ungit/manage-ungit.component.html
@@ -17,14 +17,15 @@
   ~ under the License.
   -->
 
-<modal-dialog #bindDialog modalClass="manage-ungit modal-xxl">
-  <modal-header>
-    <h4 class="modal-title" id="myModalLabel">Manage Git Credentials</h4>
-  </modal-header>
-  <modal-content class="manage-ungit">
-    <mat-tab-group mat-stretch-tabs #tabGroup class="content-box">
+<div class="manage-ungit" id="dialog-box">
+  <header class="dialog-header">
+    <h4 class="modal-title">Manage Git Credentials</h4>
+    <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+  </header>
+  <div class="dialog-content tabs">
+    <mat-tab-group mat-stretch-tabs #tabGroupGit class="content-box">
       <mat-tab label="LIST">
-        <button mat-raised-button class="butt add-creds" (click)="tabGroup.selectedIndex = 1">
+        <button mat-raised-button class="butt add-creds" (click)="tabGroupGit.selectedIndex = 1">
           <i class="material-icons">people_outline</i>Add account
         </button>
         <mat-divider></mat-divider>
@@ -62,7 +63,8 @@
 
         <div class="text-center m-top-30 m-bott-10" *ngIf="editableForm && gitCredentials?.length">
           <button mat-raised-button type="button" class="butt action" (click)="cancelAllModifyings()">Cancel</button>
-          <button mat-raised-button type="button" class="butt butt-success action" (click)="editAccounts_btnClick()">Apply changes</button>
+          <button mat-raised-button type="button" class="butt butt-success action"
+            (click)="editAccounts_btnClick()">Apply changes</button>
         </div>
       </mat-tab>
       <mat-tab label="MANAGE ACCOUNT">
@@ -72,13 +74,16 @@
               <div class="control-group">
                 <label class="label">Host name</label>
                 <div class="control">
-                  <input type="text" formControlName="hostname" placeholder="Enter host name ( without http:// or https:// )">
+                  <input type="text" formControlName="hostname"
+                    placeholder="Enter host name ( without http:// or https:// )">
                 </div>
-                <span class="danger_color" *ngIf="!updateAccountCredentialsForm.controls['hostname'].valid
+                <span class="danger_color"
+                  *ngIf="!updateAccountCredentialsForm.controls['hostname'].valid
                   && updateAccountCredentialsForm.controls['hostname'].touched && !updateAccountCredentialsForm.controls['hostname'].hasError('duplicate')">
                   Hostname field is required. Please provide a qualified domain name (e.g. gitlab.com or github.com)
                 </span>
-                <span class="danger_color" *ngIf="updateAccountCredentialsForm.controls['hostname'].hasError('duplicate') && updateAccountCredentialsForm.controls['hostname'].dirty">
+                <span class="danger_color"
+                  *ngIf="updateAccountCredentialsForm.controls['hostname'].hasError('duplicate') && updateAccountCredentialsForm.controls['hostname'].dirty">
                   The Host name is already in use
                 </span>
               </div>
@@ -87,7 +92,8 @@
                 <div class="control">
                   <input type="text" formControlName="username" placeholder="Enter user name">
                 </div>
-                <span class="danger_color" *ngIf="!updateAccountCredentialsForm.controls['username'].valid && updateAccountCredentialsForm.controls['username'].touched">
+                <span class="danger_color"
+                  *ngIf="!updateAccountCredentialsForm.controls['username'].valid && updateAccountCredentialsForm.controls['username'].touched">
                   Username field is required. Please provide a valid username
                 </span>
               </div>
@@ -96,7 +102,8 @@
                 <div class="control">
                   <input type="email" formControlName="email" placeholder="Enter email">
                 </div>
-                <span class="danger_color" *ngIf="!updateAccountCredentialsForm.controls['email'].valid && updateAccountCredentialsForm.controls['email'].touched">
+                <span class="danger_color"
+                  *ngIf="!updateAccountCredentialsForm.controls['email'].valid && updateAccountCredentialsForm.controls['email'].touched">
                   Email field is required. Please provide a valid email
                 </span>
               </div>
@@ -107,7 +114,8 @@
                 <div class="control">
                   <input type="text" formControlName="login" placeholder="Enter login">
                 </div>
-                <span class="danger_color" *ngIf="!updateAccountCredentialsForm.controls['login'].valid && updateAccountCredentialsForm.controls['login'].touched">
+                <span class="danger_color"
+                  *ngIf="!updateAccountCredentialsForm.controls['login'].valid && updateAccountCredentialsForm.controls['login'].touched">
                   Login field is required. Please provide a valid login
                 </span>
               </div>
@@ -116,7 +124,8 @@
                 <div class="control">
                   <input type="password" formControlName="password" placeholder="Enter Password">
                 </div>
-                <span class="danger_color" *ngIf="!updateAccountCredentialsForm.controls['password'].valid && updateAccountCredentialsForm.controls['password'].touched">
+                <span class="danger_color"
+                  *ngIf="!updateAccountCredentialsForm.controls['password'].valid && updateAccountCredentialsForm.controls['password'].touched">
                   Field is required. Password must be at least 6 characters
                 </span>
               </div>
@@ -125,7 +134,8 @@
                 <div class="control">
                   <input type="password" formControlName="confirmPassword" placeholder="Enter Password">
                 </div>
-                <span class="danger_color" *ngIf="!updateAccountCredentialsForm.controls['confirmPassword'].valid && updateAccountCredentialsForm.controls['confirmPassword'].touched">
+                <span class="danger_color"
+                  *ngIf="!updateAccountCredentialsForm.controls['confirmPassword'].valid && updateAccountCredentialsForm.controls['confirmPassword'].touched">
                   Field is required. Please confirm a password
                 </span>
               </div>
@@ -133,11 +143,12 @@
           </div>
           <div class="text-center submit m-bott-10">
             <button mat-raised-button type="button" class="butt action" (click)="resetForm()">Clear</button>
-            <button mat-raised-button type="button" [disabled]="!updateAccountCredentialsForm.valid" (click)="assignChanges(updateAccountCredentialsForm.value)"
+            <button mat-raised-button type="button" [disabled]="!updateAccountCredentialsForm.valid"
+              (click)="assignChanges(updateAccountCredentialsForm.value)"
               class="butt butt-success action">Assign</button>
           </div>
         </form>
       </mat-tab>
     </mat-tab-group>
-  </modal-content>
-</modal-dialog>
+  </div>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/manage-ungit/manage-ungit.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/manage-ungit/manage-ungit.component.scss
index 2c17f44..60e40b1 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/manage-ungit/manage-ungit.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/manage-ungit/manage-ungit.component.scss
@@ -22,22 +22,27 @@
     height: 500px;
     padding: 25px 35px;
   }
+
   .add-creds {
-    margin: 15px 5px;
+    margin: 15px 5px 0;
   }
+
   .scrollingList {
     overflow-x: hidden;
     padding: 5px;
     height: 185px;
+
     &.info {
       display: flex;
       justify-content: center;
       height: 300px;
+
       p {
         align-self: center;
       }
     }
   }
+
   .mail-field,
   .user-field,
   .login-field {
@@ -46,6 +51,7 @@
     text-overflow: ellipsis;
     padding: 5px;
   }
+
   .hostname-field {
     width: 25%;
     overflow: hidden;
@@ -53,18 +59,22 @@
     padding: 5px;
     width: 30%;
   }
+
   .actions {
     width: 20%;
     position: relative;
     overflow: visible;
     width: 50px;
+
     span {
       position: absolute;
       top: -10px;
       left: 0;
       zoom: 0.8;
+
       &.git-actions {
         cursor: pointer;
+
         &.remove {
           left: 35px;
         }
@@ -74,37 +84,46 @@
 
   .git-form {
     display: flex;
+
     .control-group {
       width: 100%;
       font-family: 'Open Sans', sans-serif;
       padding: 10px 0 25px;
       position: relative;
+
       input[type='text'],
       input[type='password'],
       input[type='email'] {
         font-size: 14px;
       }
+
       .label {
         width: 30%;
         font-size: 14px;
       }
+
       .control {
         width: 70%;
       }
+
       .danger_color {
         position: absolute;
         top: 45px;
         padding: 0;
+        font-size: 12px;
       }
     }
+
     .col {
       padding: 30px 10px;
       width: 50%;
     }
+
     .danger_color {
       padding-top: 0;
     }
   }
+
   .submit {
     margin-top: 60px;
   }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/manage-ungit/manage-ungit.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/manage-ungit/manage-ungit.component.ts
index 2bceb72..e339acb 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/manage-ungit/manage-ungit.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/manage-ungit/manage-ungit.component.ts
@@ -29,7 +29,7 @@
   selector: 'dlab-manage-ungit',
   templateUrl: './manage-ungit.component.html',
   styleUrls: ['./manage-ungit.component.scss',
-              '../exploratory/install-libraries/install-libraries.component.scss']
+    '../exploratory/install-libraries/install-libraries.component.scss']
 })
 export class ManageUngitComponent implements OnInit {
   model: MangeUngitModel;
@@ -44,43 +44,37 @@
   public editableForm: boolean = false;
   public updateAccountCredentialsForm: FormGroup;
 
-  @ViewChild('bindDialog') bindDialog;
-  @ViewChild('tabGroup') tabGroup;
+  @ViewChild('tabGroupGit') tabGroupGit;
 
   constructor(
+    public toastr: ToastrService,
+    public dialog: MatDialog,
+    public dialogRef: MatDialogRef<ManageUngitComponent>,
     private manageUngitService: ManageUngitService,
     private _fb: FormBuilder,
-    public dialog: MatDialog,
-    public toastr: ToastrService
   ) {
     this.model = MangeUngitModel.getDefault(manageUngitService);
   }
 
   ngOnInit() {
-    this.bindDialog.onClosing = () => this.cancelAllModifyings();
-
     this.initFormModel();
-    this.getGitCredentials();
+    this.model.getGitCredentials().subscribe(
+      (credentials: any) => {
+        this.gitCredentials = credentials.git_creds || [];
+        this.open();
+      }, () => this.open());
   }
 
-  public open(param): void {
-    if (!this.bindDialog.isOpened)
-      this.model = new MangeUngitModel(response => { },
+  public open(): void {
+    this.model = new MangeUngitModel(() => { },
       error => this.toastr.error(error.message || 'Manage git credentials failed!', 'Oops!'),
       () => {
-        this.bindDialog.open(param);
-
-        if (!this.gitCredentials.length)
-          this.tabGroup.selectedIndex = 1;
+        // if (!this.gitCredentials.length)
+        //   this.tabGroupGit.selectedIndex = 1;
       },
       this.manageUngitService);
   }
 
-  public close(): void {
-    if (this.bindDialog.isOpened)
-      this.bindDialog.close();
-  }
-
   public resetForm(): void {
     this.initFormModel();
     this.currentEditableItem = null;
@@ -93,7 +87,7 @@
   }
 
   public editSpecificAccount(item: AccountCredentials) {
-    this.tabGroup.selectedIndex = 1;
+    this.tabGroupGit.selectedIndex = 1;
     this.currentEditableItem = item;
 
     this.updateAccountCredentialsForm = this._fb.group({
@@ -128,13 +122,13 @@
 
     this.gitCredentials = modifiedCredentials;
     this.editableForm = true;
-    this.tabGroup.selectedIndex = 0;
+    this.tabGroupGit.selectedIndex = 0;
     this.resetForm();
   }
 
   public editAccounts_btnClick() {
     this.model.confirmAction(this.gitCredentials);
-    this.tabGroup.selectedIndex = 0;
+    this.tabGroupGit.selectedIndex = 0;
     this.editableForm = false;
     this.toastr.success('Git credentials updated successfully!', 'Success!');
   }
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/index.ts b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/index.ts
index ea94971..39a9732 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/index.ts
@@ -23,11 +23,11 @@
 import { MaterialModule } from '../../shared/material.module';
 import { ResourcesGridComponent } from './resources-grid.component';
 import { ComputationalResourcesModule } from '../computational/computational-resources-list';
-import { ModalModule, ConfirmationDialogModule, BubbleModule } from '../../shared';
+import { ConfirmationDialogModule, BubbleModule } from '../../shared';
 import { ComputationalResourceCreateDialogModule } from '../computational/computational-resource-create-dialog';
 import { DetailDialogModule } from '../exploratory/detail-dialog';
 import { FormControlsModule } from '../../shared/form-controls';
-import { CostDetailsDialogModule } from '../billing/cost-details-dialog';
+import { CostDetailsDialogModule } from '../exploratory/cost-details-dialog';
 import { InstallLibrariesModule } from '../exploratory/install-libraries';
 import { AmiCreateDialogModule } from '../exploratory/ami-create-dialog';
 import { SchedulerModule } from '../scheduler';
@@ -38,7 +38,6 @@
     CommonModule,
     RouterModule,
     ComputationalResourcesModule,
-    ModalModule,
     ConfirmationDialogModule,
     BubbleModule,
     DetailDialogModule,
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.css b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.css
index ec1d129..f013f2d 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.css
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.css
@@ -131,11 +131,11 @@
   font-size: 12px;
 }
 
-.dashboard_table .status {
+.data-grid .status {
   text-transform: capitalize;
 }
 
-.dashboard_table .list-menu {
+.data-grid .list-menu {
   left: auto;
   margin-left: 0;
   right: 15px;
@@ -149,6 +149,7 @@
 .settings {
   position: relative;
 }
+
 .settings .disabled {
   opacity: 0.4;
   cursor: not-allowed;
@@ -165,53 +166,55 @@
   cursor: pointer;
 }
 
-.dashboard_table .list-menu li {
+.data-grid .list-menu li {
   font-size: 14px;
   border-bottom: 1px solid #edf1f5;
-  padding: 12px 15px;
+  padding: 8px 15px;
   cursor: pointer;
   margin: 5px -5px;
   color: #577289;
   transition: all 0.45s ease-in-out;
 }
-.dashboard_table .list-menu a.navigate {  
+
+.data-grid .list-menu a.navigate {
   text-decoration: none;
   color: #577289;
   transition: all 0.45s ease-in-out;
 }
 
-.dashboard_table .list-menu li i {
+.data-grid .list-menu li i {
   font-size: 18px;
   padding-right: 5px;
   vertical-align: bottom;
 }
 
-.dashboard_table .list-menu li:hover,
-.dashboard_table .list-menu li:hover a {
+.data-grid .list-menu li:hover,
+.data-grid .list-menu li:hover a {
   background: none !important;
   color: #36afd5;
 }
 
-.dashboard_table .list-menu li:last-child {
+.data-grid .list-menu li:last-child {
   border-bottom: 0;
 }
 
-.dashboard_table .list-menu ul {
+.data-grid .list-menu ul {
   margin-bottom: 0;
 }
 
-.dashboard_table .list-menu .active-items li {
+.data-grid .list-menu .active-items li {
   border-bottom: 1px solid #edf1f5;
 }
 
-.dashboard_table .message_block {
+.data-grid .message_block {
   background: #edf6f9;
 }
+
 .message_block td {
   text-align: left !important;
 }
 
-.dashboard_table .total_cost {
+.data-grid .total_cost {
   display: inline-block;
   width: 70%;
   color: #455c74;
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 d5536c7..840fcd6 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
@@ -17,10 +17,10 @@
   ~ under the License.
   -->
 
-<table class="dashboard_table">
+<table class="dashboard_table data-grid">
   <tr>
-    <th *ngFor="let column of filteringColumns"
-        ngClass="{{column.className || ''}}" [hidden]="column.name === 'cost' && !healthStatus?.billingEnabled">
+    <th *ngFor="let column of filteringColumns" ngClass="{{column.className || ''}}"
+      [hidden]="column.name === 'cost' && !healthStatus?.billingEnabled">
       {{column.title}}
       <button mat-icon-button *ngIf="column.filtering" aria-label="More" class="ar" (click)="toggleFilterRow()">
         <i class="material-icons">
@@ -33,16 +33,21 @@
 
   <tr *ngIf="filteredEnvironments && collapseFilterRow" class="filter-row">
     <td>
-      <input placeholder="Filter by environment name" type="text" class="form-control filter-field" [value]="filterForm.name" (input)="filterForm.name = $event.target.value" />
+      <input placeholder="Filter by environment name" type="text" class="form-control filter-field"
+        [value]="filterForm.name" (input)="filterForm.name = $event.target.value" />
     </td>
     <td>
-      <multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="'statuses'" [items]="filterConfiguration.statuses" [model]="filterForm.statuses"></multi-select-dropdown>
+      <multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="'statuses'"
+        [items]="filterConfiguration.statuses" [model]="filterForm.statuses"></multi-select-dropdown>
     </td>
     <td>
-      <multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="DICTIONARY.cloud_provider === 'aws' ? 'shapes': 'sizes'" [items]="filterConfiguration.shapes" [model]="filterForm.shapes"></multi-select-dropdown>
+      <multi-select-dropdown (selectionChange)="onUpdate($event)"
+        [type]="DICTIONARY.cloud_provider === 'aws' ? 'shapes': 'sizes'" [items]="filterConfiguration.shapes"
+        [model]="filterForm.shapes"></multi-select-dropdown>
     </td>
     <td>
-      <multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="'resources'" [items]="filterConfiguration.resources" [model]="filterForm.resources"></multi-select-dropdown>
+      <multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="'resources'"
+        [items]="filterConfiguration.resources" [model]="filterForm.resources"></multi-select-dropdown>
     </td>
     <td *ngIf="healthStatus?.billingEnabled"></td>
     <td>
@@ -51,37 +56,44 @@
           <i class="material-icons">close</i>
         </button>
 
-        <button mat-icon-button class="btn apply" (click)="applyFilter_btnClick(filterForm)" [disabled]="filteredEnvironments.length == 0 && !filtering">
+        <button mat-icon-button class="btn apply" (click)="applyFilter_btnClick(filterForm)"
+          [disabled]="filteredEnvironments.length == 0 && !filtering">
           <i class="material-icons" [ngClass]="{'not-allowed': filteredEnvironments.length == 0 && !filtering}">done</i>
         </button>
       </div>
     </td>
   </tr>
 
-  <tr *ngIf="(!filteredEnvironments) && !filtering || (filteredEnvironments.length == 0) && !filtering" class="message_block">
-    <td [colSpan]="!healthStatus?.billingEnabled ? filteringColumns.length -1 : filteringColumns.length">To start working, please, create new environment</td>
+  <tr *ngIf="(!filteredEnvironments) && !filtering || (filteredEnvironments.length == 0) && !filtering"
+    class="message_block">
+    <td [colSpan]="!healthStatus?.billingEnabled ? filteringColumns.length -1 : filteringColumns.length">To start
+      working, please, create new environment</td>
   </tr>
 
   <tr *ngIf="(filteredEnvironments.length == 0) && filtering" class="message_block">
-    <td [colSpan]="!healthStatus?.billingEnabled ? filteringColumns.length -1 : filteringColumns.length">No matches found</td>
+    <td [colSpan]="!healthStatus?.billingEnabled ? filteringColumns.length -1 : filteringColumns.length">No matches
+      found</td>
   </tr>
 
-  <tr *ngFor="let env of filteredEnvironments;" class="dashboard_table_body" [ngClass]="{'dropdown-outscreen': isOutscreenDropdown}">
+  <tr *ngFor="let env of filteredEnvironments;" class="dashboard_table_body"
+    [ngClass]="{'dropdown-outscreen': isOutscreenDropdown}">
     <td (click)="printDetailEnvironmentModal(env)">{{env.name}}</td>
     <td class="status" ngClass="{{env.status.toLowerCase() || ''}}">{{ env.status | underscoreless }}</td>
     <td>{{env.shape}}</td>
     <td>
-      <computational-resources-list [resources]="env.resources" [environment]="env" [healthStatus]="healthStatus?.status" (buildGrid)="buildGrid($event)"></computational-resources-list>
+      <computational-resources-list [resources]="env.resources" [environment]="env" (buildGrid)="buildGrid($event)">
+      </computational-resources-list>
     </td>
     <td *ngIf="healthStatus?.billingEnabled">
-      <span class="total_cost">{{ env.cost || 'N/A' }} {{env.currency_code || ''}}</span>
-      <span (click)="env.billing && printCostDetails(env)" class="currency_details" [ngClass]="{'not-allowed' : !env.billing}">
+      <span class="total_cost">{{ env.cost || 'N/A' }} {{ env.currency_code || '' }}</span>
+      <span (click)="env.billing && printCostDetails(env)" class="currency_details"
+        [ngClass]="{ 'not-allowed' : !env.billing }">
         <i class="material-icons">help_outline</i>
       </span>
     </td>
     <td class="settings">
       <span #settings (click)="actions.toggle($event, settings)" class="actions"
-            [ngClass]="{'disabled': env.status.toLowerCase() == 'creating' || healthStatus?.status === 'error'}">
+        [ngClass]="{ 'disabled': env.status.toLowerCase() === 'creating' }">
       </span>
 
       <bubble-up #actions class="list-menu" position="bottom-left" alternative="top-left">
@@ -90,50 +102,48 @@
                 && env.status !== 'terminating'
                 && env.status !== 'terminated'
                 && env.status !== 'creating image'">
-            <li *ngIf="env.status !== 'stopped' && env.status !== 'stopping' && env.status !== 'starting' && env.status !== 'creating image'"
-                matTooltip="Unable to stop notebook because at least one computational resource is in progress"
-                matTooltipPosition="above"
-                [matTooltipDisabled]="!isResourcesInProgress(env)">
-                <div (click)="exploratoryAction(env, 'stop')" [ngClass]="{'not-allowed': isResourcesInProgress(env) }">
-                  <i class="material-icons">pause_circle_outline</i>
-                  <span>Stop</span>
-                </div>
+            <li
+              *ngIf="env.status !== 'stopped' && env.status !== 'stopping' && env.status !== 'starting' && env.status !== 'creating image'"
+              matTooltip="Unable to stop notebook because at least one computational resource is in progress"
+              matTooltipPosition="above" [matTooltipDisabled]="!isResourcesInProgress(env)">
+              <div (click)="exploratoryAction(env, 'stop')" [ngClass]="{'not-allowed': isResourcesInProgress(env) }">
+                <i class="material-icons">pause_circle_outline</i>
+                <span>Stop</span>
+              </div>
             </li>
             <li *ngIf="env.status.toLowerCase() === 'stopped' || env.status.toLowerCase() === 'stopping'"
-                matTooltip="Unable to run notebook until it will be stopped"
-                matTooltipPosition="above"
-                [matTooltipDisabled]="!isResourcesInProgress(env) && env.status.toLowerCase() !== 'stopping'">
-              <div (click)="exploratoryAction(env, 'run')" [ngClass]="{'not-allowed': isResourcesInProgress(env) || env.status.toLowerCase() === 'stopping' }">
+              matTooltip="Unable to run notebook until it will be stopped" matTooltipPosition="above"
+              [matTooltipDisabled]="!isResourcesInProgress(env) && env.status.toLowerCase() !== 'stopping'">
+              <div (click)="exploratoryAction(env, 'run')"
+                [ngClass]="{'not-allowed': isResourcesInProgress(env) || env.status.toLowerCase() === 'stopping' }">
                 <i class="material-icons">play_circle_outline</i>
                 <span>Run</span>
               </div>
             </li>
             <li *ngIf="env.status.toLowerCase() === 'running' || env.status.toLowerCase() === 'stopped'"
-                matTooltip="Unable to terminate notebook because at least one computational resource is in progress"
-                matTooltipPosition="above"
-                [matTooltipDisabled]="!isResourcesInProgress(env)">
-              <div (click)="exploratoryAction(env, 'terminate')" [ngClass]="{'not-allowed': isResourcesInProgress(env) }">
+              matTooltip="Unable to terminate notebook because at least one computational resource is in progress"
+              matTooltipPosition="above" [matTooltipDisabled]="!isResourcesInProgress(env)">
+              <div (click)="exploratoryAction(env, 'terminate')"
+                [ngClass]="{'not-allowed': isResourcesInProgress(env) }">
                 <i class="material-icons">phonelink_off</i>
                 <span>Terminate</span>
               </div>
             </li>
-            <li (click)="exploratoryAction(env, 'deploy')"
-                *ngIf="env.status != 'stopping'
+            <li (click)="exploratoryAction(env, 'deploy')" *ngIf="env.status != 'stopping'
                 && env.status !== 'stopped'
                 && env.status !== 'starting'
                 && env.status !== 'creating image'">
               <i class="material-icons">memory</i>
               <span>Add compute</span>
             </li>
-            <li (click)="exploratoryAction(env, 'schedule')"
-                *ngIf="env.status.toLowerCase() === 'running'
+            <li (click)="exploratoryAction(env, 'schedule')" *ngIf="env.status.toLowerCase() === 'running'
                 || env.status.toLowerCase() === 'stopped'">
-                <i class="material-icons">schedule</i>
+              <i class="material-icons">schedule</i>
               <span>Scheduler</span>
             </li>
           </div>
           <li (click)="exploratoryAction(env, 'ami')"
-              *ngIf="env.status === 'running' && DICTIONARY.cloud_provider !== 'gcp'">
+            *ngIf="env.status === 'running' && DICTIONARY.cloud_provider !== 'gcp'">
             <i class="material-icons">view_module</i>
             <span>Create {{ DICTIONARY.image }}</span>
           </li>
@@ -142,7 +152,7 @@
             <span>Manage libraries</span>
           </li>
           <li>
-            <a target="_blank" [routerLink]="['/terminal',  env.ip]" class="navigate">
+            <a target="_blank" [attr.href]="'/#/terminal/' + env.private_ip" class="navigate">
               <i class="material-icons">laptop</i>
               <span>Open terminal</span>
             </a>
@@ -152,11 +162,3 @@
     </td>
   </tr>
 </table>
-
-<computational-resource-create-dialog #computationalResourceModal (buildGrid)="buildGrid()"></computational-resource-create-dialog>
-<confirmation-dialog #confirmationDialog (buildGrid)="buildGrid()"></confirmation-dialog>
-<detail-dialog #detailDialog (buildGrid)="buildGrid()"></detail-dialog>
-<cost-details-dialog #costDetailsDialog></cost-details-dialog>
-<install-libraries #installLibs (buildGrid)="buildGrid()"></install-libraries>
-<dlab-scheduler #envScheduler (buildGrid)="buildGrid()"></dlab-scheduler>
-<dlab-ami-create-dialog #createAmi (buildGrid)="buildGrid()"></dlab-ami-create-dialog>
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 1a5564b..fc2eaf0 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
@@ -18,16 +18,24 @@
  */
 /* tslint:disable:no-empty */
 
-import { Component, ViewChild, OnInit } from '@angular/core';
+import { Component, OnInit } from '@angular/core';
 import { ToastrService } from 'ngx-toastr';
+import { MatDialog } from '@angular/material';
 
 import { UserResourceService } from '../../core/services';
-import { CreateResourceModel } from './create-resource.model';
-import { ResourcesGridRowModel } from './resources-grid.model';
+
+import { ExploratoryModel } from './resources-grid.model';
 import { FilterConfigurationModel } from './filter-configuration.model';
-import { GeneralEnvironmentStatus } from '../../management/management.model';
+import { GeneralEnvironmentStatus } from '../../administration/management/management.model';
 import { ConfirmationDialogType } from '../../shared';
-import { SortUtil } from '../../core/util';
+import { SortUtil, 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';
 
@@ -40,27 +48,16 @@
 export class ResourcesGridComponent implements OnInit {
   readonly DICTIONARY = DICTIONARY;
 
-  environments: Array<ResourcesGridRowModel>;
-  filteredEnvironments: Array<ResourcesGridRowModel> = [];
+  environments: Array<ExploratoryModel>;
+  filteredEnvironments: Array<ExploratoryModel> = [];
   filterConfiguration: FilterConfigurationModel;
   filterForm: FilterConfigurationModel = new FilterConfigurationModel('', [], [], [], '');
-  model = new CreateResourceModel('', '');
-  notebookName: string;
+
   isOutscreenDropdown: boolean;
   collapseFilterRow: boolean = false;
   filtering: boolean = false;
   activeFiltering: boolean = false;
   healthStatus: GeneralEnvironmentStatus;
-  delimitersRegex = /[-_]?/g;
-
-  @ViewChild('computationalResourceModal') computationalResourceModal;
-  @ViewChild('confirmationDialog') confirmationDialog;
-  @ViewChild('detailDialog') detailDialog;
-  @ViewChild('costDetailsDialog') costDetailsDialog;
-  @ViewChild('installLibs') installLibraries;
-  @ViewChild('envScheduler') scheduler;
-  @ViewChild('createAmi') createAMI;
-
 
   public filteringColumns: Array<any> = [
     { title: 'Environment name', name: 'name', className: 'th_name', filtering: {} },
@@ -72,8 +69,9 @@
   ];
 
   constructor(
+    public toastr: ToastrService,
     private userResourceService: UserResourceService,
-    public toastr: ToastrService
+    private dialog: MatDialog
   ) {}
 
   ngOnInit(): void {
@@ -85,7 +83,7 @@
   }
 
   getDefaultFilterConfiguration(): void {
-    const data: Array<ResourcesGridRowModel> = this.environments;
+    const data: Array<ExploratoryModel> = this.environments;
     const shapes = [], statuses = [], resources = [];
 
     data.forEach((item: any) => {
@@ -108,8 +106,8 @@
   applyFilter_btnClick(config: FilterConfigurationModel) {
     this.filtering = true;
 
-    // let filteredData: Array<ResourcesGridRowModel> = this.environments.map(env => (<any>Object).assign({}, env));
-    let filteredData: Array<ResourcesGridRowModel> = this.environments.map(env => (<any>Object).create(env));
+    // let filteredData: Array<ExploratoryModel> = this.environments.map(env => (<any>Object).assign({}, env));
+    let filteredData: Array<ExploratoryModel> = this.environments.map(env => (<any>Object).create(env));
     const containsStatus = (list, selectedItems) => {
       return list.filter((item: any) => { if (selectedItems.indexOf(item.status) !== -1) return item; });
     };
@@ -198,10 +196,9 @@
   }
 
   buildGrid(): void {
-
     this.userResourceService.getUserProvisionedResources()
       .subscribe((result) => {
-        this.environments = this.loadEnvironments(result.exploratory, result.shared);
+        this.environments = ExploratoryModel.loadEnvironments(result.exploratory, result.shared);
         this.getDefaultFilterConfiguration();
 
         (this.environments.length) ? this.getUserPreferences() : this.filteredEnvironments = [];
@@ -211,47 +208,12 @@
   containsNotebook(notebook_name: string): boolean {
     if (notebook_name)
       for (let index = 0; index < this.environments.length; index++)
-        if (this.delimitersFiltering(notebook_name) === this.delimitersFiltering(this.environments[index].name))
+        if (CheckUtils.delimitersFiltering(notebook_name) === CheckUtils.delimitersFiltering(this.environments[index].name))
           return true;
 
     return false;
   }
 
-  public delimitersFiltering(notebook_name): string {
-    return notebook_name.replace(this.delimitersRegex, '').toString().toLowerCase();
-  }
-
-  loadEnvironments(exploratoryList: Array<any>, sharedDataList: any): Array<ResourcesGridRowModel> {
-    if (exploratoryList && sharedDataList) {
-      return exploratoryList.map((value) => {
-        return new ResourcesGridRowModel(value.exploratory_name,
-          value.template_name,
-          value.image,
-          value.status,
-          value.shape,
-          value.computational_resources,
-          value.up_time,
-          value.exploratory_url,
-          sharedDataList.edge_node_ip,
-          value.exploratory_user,
-          value.exploratory_pass,
-          sharedDataList[DICTIONARY.bucket_name],
-          sharedDataList[DICTIONARY.shared_bucket_name],
-          value.error_message,
-          value[DICTIONARY.billing.cost],
-          value[DICTIONARY.billing.currencyCode],
-          value.billing,
-          value.libs,
-          sharedDataList[DICTIONARY.user_storage_account_name],
-          sharedDataList[DICTIONARY.shared_storage_account_name],
-          sharedDataList[DICTIONARY.datalake_name],
-          sharedDataList[DICTIONARY.datalake_user_directory_name],
-          sharedDataList[DICTIONARY.datalake_shared_directory_name],
-        );
-      });
-    }
-  }
-
   getUserPreferences(): void {
     this.userResourceService.getUserPreferences()
       .subscribe((result: FilterConfigurationModel) => {
@@ -276,17 +238,19 @@
   }
 
   printDetailEnvironmentModal(data): void {
-    this.detailDialog.open({ isFooter: false }, data);
+    this.dialog.open(DetailDialogComponent, { data: data, panelClass: 'modal-lg' })
+               .afterClosed().subscribe(() => this.buildGrid());
   }
 
   printCostDetails(data): void {
-    this.costDetailsDialog.open({ isFooter: false }, data);
+    this.dialog.open(CostDetailsDialogComponent, { data: data, panelClass: 'modal-xl' })
+               .afterClosed().subscribe(() => this.buildGrid());
   }
 
   exploratoryAction(data, action: string) {
     if (action === 'deploy') {
-      this.notebookName = data.name;
-      this.computationalResourceModal.open({ isFooter: false }, data, this.environments);
+      this.dialog.open(ComputationalResourceCreateDialogComponent, { data: { notebook: data, full_list: this.environments}, panelClass: 'modal-xxl'})
+                 .afterClosed().subscribe(() => this.buildGrid());
     } else if (action === 'run') {
       this.userResourceService
         .runExploratoryEnvironment({ notebook_instance_name: data.name })
@@ -294,15 +258,20 @@
           () => this.buildGrid(),
           error => this.toastr.error(error.message || 'Exploratory starting failed!', 'Oops!'));
     } else if (action === 'stop') {
-      this.confirmationDialog.open({ isFooter: false }, data, ConfirmationDialogType.StopExploratory);
+      this.dialog.open(ConfirmationDialogComponent, { data: { notebook: data, type: ConfirmationDialogType.StopExploratory }, panelClass: 'modal-sm'})
+                 .afterClosed().subscribe(() => this.buildGrid());
     } else if (action === 'terminate') {
-      this.confirmationDialog.open({ isFooter: false }, data, ConfirmationDialogType.TerminateExploratory);
+      this.dialog.open(ConfirmationDialogComponent, {data: { notebook: data, type: ConfirmationDialogType.TerminateExploratory }, panelClass: 'modal-sm'})
+                 .afterClosed().subscribe(() => this.buildGrid());
     } else if (action === 'install') {
-      this.installLibraries.open({ isFooter: false }, data);
+      this.dialog.open(InstallLibrariesComponent, { data: data, panelClass: 'modal-fullscreen' })
+                 .afterClosed().subscribe(() => this.buildGrid());
     } else if (action === 'schedule') {
-      this.scheduler.open({ isFooter: false }, data, 'EXPLORATORY');
+      this.dialog.open(SchedulerComponent, { data: {notebook: data, type: 'EXPLORATORY'}, panelClass: 'modal-xl-s' })
+                 .afterClosed().subscribe(() => this.buildGrid());
     } else if (action === 'ami') {
-      this.createAMI.open({ isFooter: false }, data);
+      this.dialog.open(AmiCreateDialogComponent, { data: data, panelClass: 'modal-sm' })
+                 .afterClosed().subscribe(() => this.buildGrid());
     }
   }
 }
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 edd2af6..f1c83f3 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
@@ -16,8 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+import { DICTIONARY } from '../../../dictionary/global.dictionary';
 
-export class ResourcesGridRowModel {
+export class ExploratoryModel {
+  readonly DICTIONARY = DICTIONARY;
+
   constructor(
     public name: Array<any>,
     public template_name: string,
@@ -27,7 +30,8 @@
     public resources: Array<any>,
     public time: string,
     public url: Array<any>,
-    public ip: string,
+    public node_ip: string,
+    public private_ip: string,
     public username: string,
     public password: string,
     public bucket_name: string,
@@ -41,6 +45,44 @@
     public shared_account_name: string,
     public datalake_name: string,
     public datalake_directory: string,
-    public datalake_shared_directory: string
+    public datalake_shared_directory: string,
+    public project: string,
+    public endpoint: string,
+    public tags: any,
   ) { }
+
+  public static loadEnvironments(exploratoryList: Array<any>, sharedDataList: any): Array<ExploratoryModel> {
+    if (exploratoryList && sharedDataList) {
+      return exploratoryList.map((value) => {
+        return new ExploratoryModel(value.exploratory_name,
+          value.template_name,
+          value.image,
+          value.status,
+          value.shape,
+          value.computational_resources,
+          value.up_time,
+          value.exploratory_url,
+          sharedDataList.edge_node_ip,
+          value.private_ip,
+          value.exploratory_user,
+          value.exploratory_pass,
+          sharedDataList[DICTIONARY.bucket_name],
+          sharedDataList[DICTIONARY.shared_bucket_name],
+          value.error_message,
+          value[DICTIONARY.billing.cost],
+          value[DICTIONARY.billing.currencyCode],
+          value.billing,
+          value.libs,
+          sharedDataList[DICTIONARY.user_storage_account_name],
+          sharedDataList[DICTIONARY.shared_storage_account_name],
+          sharedDataList[DICTIONARY.datalake_name],
+          sharedDataList[DICTIONARY.datalake_user_directory_name],
+          sharedDataList[DICTIONARY.datalake_shared_directory_name],
+          value.project,
+          value.endpoint,
+          value.tags
+        );
+      });
+    }
+  }
 }
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 e913ca4..c4fdad8 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
@@ -19,7 +19,8 @@
 
 <div class="sub-nav base-retreat">
   <div>
-    <button mat-raised-button class="butt butt-create" [disabled]="userUploadAccessKeyState == 202 || healthStatus?.status === 'error'" (click)="createNotebook_btnClick()">
+    <button mat-raised-button class="butt butt-create" (click)="createEnvironment()"
+      [disabled]="!healthStatus?.projectAssigned">
       <i class="material-icons">add</i>Create new
     </button>
   </div>
@@ -41,12 +42,4 @@
   </div>
 </div>
 
-<div *ngIf="userUploadAccessKeyState == 500" class="warning-alert base-retreat">
-  <span class="material-icons">priority_high</span>
-  Error happened during user access key upload. Please try to reupload the key.
-</div>
-
 <resources-grid></resources-grid>
-
-<exploratory-environment-create-dialog #createAnalyticalModal (buildGrid)="refreshGrid()"></exploratory-environment-create-dialog>
-<dlab-manage-ungit #manageUngitDialog></dlab-manage-ungit>
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 e718a6b..e4a13ae 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
@@ -22,14 +22,6 @@
 }
 
 .butt {
-  &.butt-create {
-    color: #35afd5;
-  }
-  &.butt-create {
-    &:disabled{
-      color: #577289!important;
-    }
-  }
   &.butt-tool {
     margin-right: 10px;
   }
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 8eac860..d59e4a0 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
@@ -20,11 +20,13 @@
 import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core';
 import { Subscription } from 'rxjs';
 import { ToastrService } from 'ngx-toastr';
+import { MatDialog } from '@angular/material';
 
 import { ResourcesGridComponent } from './resources-grid/resources-grid.component';
-import { UserAccessKeyService, HealthStatusService } from '../core/services';
-import { ResourcesGridRowModel } from './resources-grid/resources-grid.model';
-import { HTTP_STATUS_CODES, FileUtils } from '../core/util';
+import { ExploratoryEnvironmentCreateComponent } from './exploratory/create-environment';
+import { ExploratoryModel } from './resources-grid/resources-grid.model';
+import { HealthStatusService } from '../core/services';
+import { ManageUngitComponent } from './manage-ungit/manage-ungit.component';
 
 @Component({
   selector: 'dlab-resources',
@@ -32,48 +34,25 @@
   styleUrls: ['./resources.component.scss']
 })
 
-export class ResourcesComponent implements OnInit, OnDestroy {
-
-  public userUploadAccessKeyState: number;
-  public exploratoryEnvironments: Array<ResourcesGridRowModel> = [];
+export class ResourcesComponent implements OnInit {
+  public exploratoryEnvironments: Array<ExploratoryModel> = [];
   public healthStatus: any;
 
-  @ViewChild('createAnalyticalModal') createAnalyticalModal;
-  @ViewChild('manageUngitDialog') manageUngitDialog;
   @ViewChild(ResourcesGridComponent) resourcesGrid: ResourcesGridComponent;
 
-  subscriptions: Subscription = new Subscription();
-
   constructor(
-    private userAccessKeyService: UserAccessKeyService,
+    public toastr: ToastrService,
     private healthStatusService: HealthStatusService,
-    public toastr: ToastrService
-  ) {
-    this.userUploadAccessKeyState = HTTP_STATUS_CODES.NOT_FOUND;
-  }
+    private dialog: MatDialog
+  ) { }
 
   ngOnInit() {
     this.getEnvironmentHealthStatus();
-    this.createAnalyticalModal.resourceGrid = this.resourcesGrid;
-
-    this.subscriptions.add(this.userAccessKeyService.accessKeyEmitter.subscribe(response => {
-      if (response) this.userUploadAccessKeyState = response.status;
-    }));
-    this.subscriptions.add(this.userAccessKeyService.keyUploadProccessEmitter.subscribe(response => {
-      if (response) this.refreshGrid();
-    }));
   }
 
-  ngOnDestroy() {
-    this.subscriptions.unsubscribe();
-  }
-
-  public createNotebook_btnClick(): void {
-    if (this.userUploadAccessKeyState === HTTP_STATUS_CODES.OK) {
-      if (!this.createAnalyticalModal.isOpened) this.createAnalyticalModal.open({ isFooter: false });
-    } else {
-      this.userAccessKeyService.initialUserAccessKeyCheck();
-    }
+  public createEnvironment(): void {
+    this.dialog.open(ExploratoryEnvironmentCreateComponent, { data: this.resourcesGrid, panelClass: 'modal-lg' })
+      .afterClosed().subscribe(() => this.refreshGrid());
   }
 
   public refreshGrid(): void {
@@ -91,17 +70,16 @@
   }
 
   public manageUngit(): void {
-    if (!this.manageUngitDialog.isOpened)
-        this.manageUngitDialog.open({ isFooter: false });
+    this.dialog.open(ManageUngitComponent, { panelClass: 'modal-xxl' })
+      .afterClosed().subscribe(() => this.refreshGrid());
   }
 
   private getEnvironmentHealthStatus() {
     this.healthStatusService.getEnvironmentHealthStatus().subscribe(
-        (result: any) => {
-          this.healthStatus = result;
-          this.resourcesGrid.healthStatus = this.healthStatus;
-          this.userAccessKeyService.initialUserAccessKeyCheck();
-        },
+      (result: any) => {
+        this.healthStatus = result;
+        this.resourcesGrid.healthStatus = this.healthStatus;
+      },
       error => this.toastr.error(error.message, 'Oops!'));
   }
 }
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 59cfbad..9f3e25d 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
@@ -24,25 +24,17 @@
 import { MaterialModule } from '../shared/material.module';
 import { ResourcesComponent } from './resources.component';
 import { ResourcesGridModule } from './resources-grid';
-import { ExploratoryEnvironmentCreateDialogModule } from './exploratory/exploratory-environment-create-dialog';
+import { ExploratoryEnvironmentCreateModule } from './exploratory/create-environment';
 import { ManageUngitComponent } from './manage-ungit/manage-ungit.component';
 import { ConfirmDeleteAccountDialog } from './manage-ungit/manage-ungit.component';
-import {
-  ModalModule,
-  ProgressDialogModule,
-  UploadKeyDialogModule
-} from '../shared';
 
 @NgModule({
   imports: [
     CommonModule,
-    ModalModule,
     FormsModule,
     ReactiveFormsModule,
     ResourcesGridModule,
-    ProgressDialogModule,
-    UploadKeyDialogModule,
-    ExploratoryEnvironmentCreateDialogModule,
+    ExploratoryEnvironmentCreateModule,
     MaterialModule
   ],
   declarations: [
@@ -50,7 +42,7 @@
     ManageUngitComponent,
     ConfirmDeleteAccountDialog
   ],
-  entryComponents: [ConfirmDeleteAccountDialog],
+  entryComponents: [ManageUngitComponent, ConfirmDeleteAccountDialog],
   exports: [ResourcesComponent]
 })
 export class ResourcesModule {}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/index.ts b/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/index.ts
index f407368..30dad18 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/index.ts
@@ -22,7 +22,7 @@
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
 
 import { MaterialModule } from '../../shared/material.module';
-import { ModalModule, BubbleModule } from '../../shared';
+import { BubbleModule } from '../../shared';
 import { FormControlsModule } from '../../shared/form-controls';
 import { SchedulerComponent } from './scheduler.component';
 import { TimePickerModule } from '../../shared/time-picker';
@@ -35,13 +35,13 @@
     CommonModule,
     FormsModule,
     ReactiveFormsModule,
-    ModalModule,
     FormControlsModule,
     MaterialModule,
     BubbleModule,
     TimePickerModule
   ],
   declarations: [SchedulerComponent],
+  entryComponents: [SchedulerComponent],
   exports: [SchedulerComponent]
 })
 export class SchedulerModule {}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.html
index 83d55d6..bedb7ac 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.html
@@ -17,16 +17,17 @@
   ~ under the License.
   -->
 
-<modal-dialog #bindDialog modalClass="scheduler-dialog modal-xl-s">
-  <modal-header>
+<div class="scheduler-dialog" id="dialog-box">
+  <header class="dialog-header">
     <h4 class="modal-title">Scheduler
       <span *ngIf="destination">for
         <b *ngIf="destination.type === 'EXPLORATORY'; else resource">{{ destination.name }}</b>
         <ng-template #resource><b>{{ destination.computational_name }}</b></ng-template>
       </span>
     </h4>
-  </modal-header>
-  <modal-content>
+    <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+  </header>
+  <div class="dialog-content">
     <div *ngIf="destination" class="content-box">
       <form [formGroup]="schedulerForm">
         <div class="enable-schedule">
@@ -203,10 +204,10 @@
 
       </form>
       <div class="text-center m-top-30">
-        <button mat-raised-button type="button" class="butt action" (click)="close()">Cancel</button>
+        <button mat-raised-button type="button" class="butt action" (click)="dialogRef.close()">Cancel</button>
         <button mat-raised-button type="button" class="butt butt-success action" [disabled]="enableIdleTime && !schedulerForm.controls.inactivityTime.valid"
           (click)="scheduleInstance_btnClick()">Save</button>
       </div>
     </div>
-  </modal-content>
-</modal-dialog>
\ No newline at end of file
+  </div>
+</div>
\ No newline at end of file
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.scss
index e698b24..87fa93e 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.scss
@@ -44,6 +44,7 @@
   .enable-schedule {
     display: flex;
     margin-bottom: 10px;
+    justify-content: space-between;
     .idle {
       display: flex;
       width: 50%;
@@ -171,6 +172,8 @@
       .mat-button-toggle-standalone {
         box-shadow: none;
         margin: 2px;
+        border: none;
+        color: #607D8B;
         &.mat-button-toggle-checked {
           background-color: rgba(77, 184, 218, 0.62);
           color: #ffffff;
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.ts
index 3582b11..1837e41 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/scheduler/scheduler.component.ts
@@ -17,8 +17,9 @@
  * under the License.
  */
 
-import { Component, OnInit, ViewChild, Output, EventEmitter, ViewEncapsulation, ChangeDetectorRef } from '@angular/core';
+import { Component, OnInit, ViewChild, Output, EventEmitter, ViewEncapsulation, ChangeDetectorRef, Inject } from '@angular/core';
 import { FormGroup, FormBuilder, Validators } from '@angular/forms';
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
 import { ToastrService } from 'ngx-toastr';
 
 import * as _moment from 'moment';
@@ -67,37 +68,39 @@
   public inactivityLimits = { min: 120, max: 10080 };
   public integerRegex: string = '^[0-9]*$';
 
-  @ViewChild('bindDialog') bindDialog;
+  // @ViewChild('bindDialog') bindDialog;
   @ViewChild('resourceSelect') resource_select;
-  @Output() buildGrid: EventEmitter<{}> = new EventEmitter();
+  // @Output() buildGrid: EventEmitter<{}> = new EventEmitter();
 
   constructor(
+    @Inject(MAT_DIALOG_DATA) public data: any,
+    public toastr: ToastrService,
+    public dialogRef: MatDialogRef<SchedulerComponent>,
     private formBuilder: FormBuilder,
     private schedulerService: SchedulerService,
-    private changeDetector: ChangeDetectorRef,
-    public toastr: ToastrService
+    private changeDetector: ChangeDetectorRef
   ) {}
 
   ngOnInit() {
-    this.bindDialog.onClosing = () => {
-      this.resetDialog();
-      this.buildGrid.emit();
-    };
+    // this.bindDialog.onClosing = () => {
+    //   this.resetDialog();
+    //   this.buildGrid.emit();
+    // };
+    this.open(this.data.notebook, this.data.type, this.data.resource);
   }
 
-  public open(param, notebook, type, resource?): void {
+  public open(notebook, type, resource?): void {
     this.notebook = notebook;
     this.zones = _moment.tz.names()
       .map(el => _moment.tz(el).format('Z'))
       .filter((item, pos, ar) => ar.indexOf(item) === pos)
       .sort();
 
-    if (!this.bindDialog.isOpened)
       this.model = new SchedulerModel(
         response => {
           if (response.status === HTTP_STATUS_CODES.OK) {
             this.toastr.success('Schedule data were successfully saved', 'Success!');
-            this.close();
+            this.dialogRef.close();
           }
         },
         error => this.toastr.error(error.message || 'Scheduler configuration failed!', 'Oops!'),
@@ -118,7 +121,7 @@
             this.allowInheritView = this.checkIsActiveSpark();
             this.getExploratorySchedule(this.notebook.name);
           }
-          this.bindDialog.open(param);
+          // this.bindDialog.open(param);
         },
         this.schedulerService
       );
@@ -179,7 +182,7 @@
     this.model.setInactivityTime(params).subscribe((response: any) => {
         if (response.status === HTTP_STATUS_CODES.OK) {
           this.toastr.success('Schedule data were successfully saved', 'Success!');
-          this.close();
+          this.dialogRef.close();
         }
       },
       error => this.toastr.error(error.message || 'Scheduler configuration failed!', 'Oops!'));
@@ -206,7 +209,7 @@
       .subscribe(() => {
         this.resetDialog();
         this.toastr.success('Schedule data were successfully deleted', 'Success!');
-        this.close();
+        this.dialogRef.close();
       });
   }
 
@@ -259,13 +262,13 @@
       : this.setInactivity(this.notebook.name, {...data, consider_inactivity: this.considerInactivity});
   }
 
-  public close(): void {
-    if (this.bindDialog.isOpened) {
-      this.bindDialog.close();
-    }
+  // public close(): void {
+  //   if (this.bindDialog.isOpened) {
+  //     this.bindDialog.close();
+  //   }
 
-    this.resetDialog();
-  }
+  //   this.resetDialog();
+  // }
 
   private formInit(start?: string, end?: string, terminate?: string) {
     this.schedulerForm = this.formBuilder.group({
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/index.ts b/services/self-service/src/main/resources/webapp/src/app/shared/index.ts
index 9bcd6cd..5141d40 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/index.ts
@@ -17,7 +17,6 @@
  * under the License.
  */
 
-export * from './modal-dialog';
 export * from './modal-dialog/confirmation-dialog';
 export * from './modal-dialog/progress-dialog';
 export * from './modal-dialog/key-upload-dialog';
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.html
index d9ba880..a19d773 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.html
@@ -17,8 +17,8 @@
   ~ under the License.
   -->
 
-<modal-dialog #bindDialog modalClass="confirmation-dialog modal-md">
-  <modal-header>
+<div id="dialog-box" class="confirmation-dialog">
+  <header class="dialog-header">
     <h4 class="modal-title">
       <span *ngIf="model.notebook.name && model.notebook.name !== 'edge node'">
         <span>{{ confirmationType ? 'Terminate' : 'Stop' }} notebook: {{ model.notebook.name }}</span>
@@ -27,12 +27,14 @@
         <i class="material-icons">priority_high</i>Warning
       </span>
     </h4>
-  </modal-header>
-  <modal-content>
+    <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+  </header>
+  <div class="dialog-content">
     <div class="content-box">
       <p class="info text-center">{{ model.title }}</p>
 
-      <mat-list class="resources" [hidden]="model.notebook.type === 'Edge Node' || model.notebook.name === 'edge node'
+      <mat-list class="resources"
+        [hidden]="model.notebook.type === 'Edge Node' || model.notebook.name === 'edge node'
                                   || !model.notebook.resources || model.notebook.resources.length === 0 || (!isAliveResources && !confirmationType) || onlyKilled">
         <mat-list-item class="list-header">
           <div class="cluster">Cluster</div>
@@ -41,23 +43,23 @@
         </mat-list-item>
         <div class="scrolling-content" id="scrolling">
           <mat-list-item *ngFor="let resource of model.notebook.resources"
-                        [hidden]="resource.status === 'failed' || resource.status === 'terminated' || resource.status === 'terminating' || (resource.status === 'stopped' && !confirmationType)">
+            [hidden]="resource.status === 'failed' || resource.status === 'terminated' || resource.status === 'terminating' || (resource.status === 'stopped' && !confirmationType)">
             <div class="cluster ellipsis">{{ resource.computational_name  }}</div>
             <div class="status" [ngClass]="{ 'stopped': !confirmationType && resource.image === 'docker.dlab-dataengine',
-                  'terminated': resource.image === 'docker.dlab-dataengine-service' || confirmationType }">{{ (!confirmationType && resource.image === 'docker.dlab-dataengine') ? 'Stopped' : 'Terminated' }}</div>
+                  'terminated': resource.image === 'docker.dlab-dataengine-service' || confirmationType }">
+              {{ (!confirmationType && resource.image === 'docker.dlab-dataengine') ? 'Stopped' : 'Terminated' }}</div>
             <div class="size">{{ resource[DICTIONARY[resource.image].master_node_shape] }}</div>
           </mat-list-item>
         </div>
       </mat-list>
 
       <div class="text-center m-top-20">
-        <p *ngIf="model.notebook.name">Do you want to proceed?</p>
-        <p *ngIf="model.notebook.type">Are you sure you want to continue?</p>
+        <p>Do you want to proceed?</p>
       </div>
       <div class="text-center m-top-20">
-        <button mat-raised-button type="button" class="butt action" (click)="bindDialog.close()">No</button>
+        <button mat-raised-button type="button" class="butt action" (click)="dialogRef.close()">No</button>
         <button mat-raised-button type="button" class="butt butt-success action" (click)="confirm()">Yes</button>
       </div>
     </div>
-  </modal-content>
-</modal-dialog>
+  </div>
+</div>
\ No newline at end of file
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.ts
index c1fe712..3ba0214 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/confirmation-dialog.component.ts
@@ -17,11 +17,11 @@
  * under the License.
  */
 
-import { Component, OnInit, ViewChild, Input, Output, EventEmitter, ViewEncapsulation } from '@angular/core';
+import { Component, OnInit, Inject, Input, Output, EventEmitter, ViewEncapsulation } from '@angular/core';
 import { ToastrService } from 'ngx-toastr';
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
 
 import { ConfirmationDialogModel } from './confirmation-dialog.model';
-import { ConfirmationDialogType } from './confirmation-dialog-type.enum';
 import { UserResourceService, HealthStatusService, ManageEnvironmentsService } from '../../../core/services';
 import { HTTP_STATUS_CODES } from '../../../core/util';
 import { DICTIONARY } from '../../../../dictionary/global.dictionary';
@@ -29,25 +29,28 @@
 @Component({
   selector: 'confirmation-dialog',
   templateUrl: 'confirmation-dialog.component.html',
-  styleUrls: ['./confirmation-dialog.component.scss', '../modal.component.scss'],
+  styleUrls: ['./confirmation-dialog.component.scss'],
   encapsulation: ViewEncapsulation.None
 })
 
 export class ConfirmationDialogComponent implements OnInit {
   readonly DICTIONARY = DICTIONARY;
+
   model: ConfirmationDialogModel;
   isAliveResources: boolean;
   onlyKilled: boolean = false;
+  notebook: any;
   dataengines: Array<any> = [];
   dataengineServices: Array<any> = [];
   confirmationType: number = 0;
 
-  @ViewChild('bindDialog') bindDialog;
   @Input() manageAction: boolean = false;
 
   @Output() buildGrid: EventEmitter<{}> = new EventEmitter();
 
   constructor(
+    @Inject(MAT_DIALOG_DATA) public data: any,
+    public dialogRef: MatDialogRef<ConfirmationDialogComponent>,
     private userResourceService: UserResourceService,
     private healthStatusService: HealthStatusService,
     private manageEnvironmentsService: ManageEnvironmentsService,
@@ -57,36 +60,25 @@
   }
 
   ngOnInit() {
-    this.bindDialog.onClosing = () => this.resetDialog();
-  }
-
-  public open(param, notebook: any, type: ConfirmationDialogType) {
-    this.confirmationType = type;
-
-    this.model = new ConfirmationDialogModel(type, notebook,
+    this.confirmationType = this.data.type;
+    this.notebook = this.data.notebook;
+    this.model = new ConfirmationDialogModel(this.confirmationType, this.notebook,
       response => {
-        if (response.status === HTTP_STATUS_CODES.OK) {
-          this.close();
-          this.buildGrid.emit();
-        }
+        if (response.status === HTTP_STATUS_CODES.OK) this.dialogRef.close();
       },
       error => this.toastr.error(error.message || 'Action failed!', 'Oops'),
-      this.manageAction,
+      this.data.manageAction,
       this.userResourceService,
       this.healthStatusService,
       this.manageEnvironmentsService);
 
-    this.bindDialog.open(param);
-    if (!this.confirmationType) this.filterResourcesByType(notebook.resources);
-    this.isAliveResources = this.model.isAliveResources(notebook.resources);
-    this.onlyKilled = notebook.resources ? !notebook.resources.some(el => el.status !== 'terminated') : false;
-  }
-  public confirm() {
-    this.model.confirmAction();
+    if (!this.confirmationType) this.filterResourcesByType(this.notebook.resources);
+    this.isAliveResources = this.model.isAliveResources(this.notebook.resources);
+    this.onlyKilled = this.notebook.resources ? !this.notebook.resources.some(el => el.status !== 'terminated') : false;
   }
 
-  public close() {
-    this.bindDialog.close();
+  public confirm() {
+    this.model.confirmAction();
   }
 
   private filterResourcesByType(resources) {
@@ -97,9 +89,4 @@
     .forEach(resource => {
       (resource.image === 'docker.dlab-dataengine') ? this.dataengines.push(resource) : this.dataengineServices.push(resource); });
   }
-
-  private resetDialog(): void {
-    this.dataengines = [];
-    this.dataengineServices = [];
-  }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/index.ts b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/index.ts
index 2790f28..a0a4605 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/confirmation-dialog/index.ts
@@ -20,7 +20,6 @@
 import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
 
-import { ModalModule } from '..';
 import { ConfirmationDialogComponent } from './confirmation-dialog.component';
 import { MaterialModule } from '../../material.module';
 
@@ -28,8 +27,9 @@
 export * from './confirmation-dialog-type.enum';
 
 @NgModule({
-  imports: [CommonModule, ModalModule, MaterialModule],
+  imports: [CommonModule, MaterialModule],
   declarations: [ConfirmationDialogComponent],
+  entryComponents: [ConfirmationDialogComponent],
   exports: [ConfirmationDialogComponent]
 })
 export class ConfirmationDialogModule {}
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/index.ts b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/index.ts
deleted file mode 100644
index cb3835b..0000000
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/index.ts
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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 { CommonModule } from '@angular/common';
-import { NgModule, Component } from '@angular/core';
-
-import { MaterialModule } from '../material.module';
-import { ModalComponent } from './modal.component';
-
-export * from './modal.component';
-
-@Component({
-  selector: 'modal-header',
-  template: `<ng-content></ng-content>`
-})
-export class ModalHeaderComponent {}
-
-@Component({
-  selector: 'modal-content',
-  template: `<ng-content></ng-content>`
-})
-export class ModalContentComponent {}
-
-@Component({
-  selector: 'modal-footer',
-  template: `<ng-content></ng-content>`
-})
-export class ModalFooterComponent {}
-
-@NgModule({
-  imports: [CommonModule, MaterialModule],
-  declarations: [
-    ModalComponent,
-    ModalHeaderComponent,
-    ModalContentComponent,
-    ModalFooterComponent
-  ],
-  exports: [
-    ModalComponent,
-    ModalHeaderComponent,
-    ModalContentComponent,
-    ModalFooterComponent
-  ]
-})
-export class ModalModule {}
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/key-upload-dialog/index.ts b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/key-upload-dialog/index.ts
index 58093d8..9531f32 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/key-upload-dialog/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/key-upload-dialog/index.ts
@@ -20,15 +20,15 @@
 import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
 
-import { ModalModule } from '..';
 import { UploadKeyDialogComponent } from './key-upload-dialog.component';
 import { MaterialModule } from '../../material.module';
 
 export * from './key-upload-dialog.component';
 
 @NgModule({
-  imports: [CommonModule, ModalModule, MaterialModule],
+  imports: [CommonModule, MaterialModule],
   declarations: [UploadKeyDialogComponent],
+  entryComponents: [UploadKeyDialogComponent],
   exports: [UploadKeyDialogComponent]
 })
 export class UploadKeyDialogModule {}
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/key-upload-dialog/key-upload-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/key-upload-dialog/key-upload-dialog.component.html
index 10eb2d6..ed41792 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/key-upload-dialog/key-upload-dialog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/key-upload-dialog/key-upload-dialog.component.html
@@ -17,14 +17,14 @@
   ~ under the License.
   -->
 
-<modal-dialog #bindDialog modalClass="modal-sm">
-  <modal-header>
+<div id="dialog-box" class="modal-sm">
+  <header class="dialog-header">
     <h4 class="modal-title">
       <span *ngIf="primaryUploading">Create initial infrastructure</span>
       <span *ngIf="!primaryUploading">Reupload key</span>
     </h4>
-  </modal-header>
-  <modal-content>
+  </header>
+  <div class="dialog-content">
     <div class="content-box">
       <form (submit)="uploadUserAccessKey_btnClick($event)" novalidate>
         <div class="row-wrap upload-key">
@@ -60,6 +60,5 @@
         </div>
       </form>
     </div>
-  </modal-content>
-  <modal-footer></modal-footer>
-</modal-dialog>
+  </div>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/key-upload-dialog/key-upload-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/key-upload-dialog/key-upload-dialog.component.ts
index ba4f7a4..34ca908 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/key-upload-dialog/key-upload-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/key-upload-dialog/key-upload-dialog.component.ts
@@ -17,8 +17,9 @@
  * under the License.
  */
 
-import { Component, OnInit, EventEmitter, Input, Output, ViewChild } from '@angular/core';
+import { Component, OnInit, EventEmitter, Input, Output, ViewChild, Inject } from '@angular/core';
 import { ToastrService } from 'ngx-toastr';
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
 
 import { KeyUploadDialogModel } from './key-upload.model';
 import { UserAccessKeyService } from '../../../core/services';
@@ -33,12 +34,13 @@
   model: KeyUploadDialogModel;
   @Input() primaryUploading: boolean = true;
 
-  @ViewChild('bindDialog') bindDialog;
   @ViewChild('userAccessKeyUploadControl') userAccessKeyUploadControl;
   @Output() checkInfrastructureCreationProgress: EventEmitter<{}> = new EventEmitter();
   @Output() generateUserKey: EventEmitter<{}> = new EventEmitter();
 
   constructor(
+    @Inject(MAT_DIALOG_DATA) public data: any,
+    public dialogRef: MatDialogRef<UploadKeyDialogComponent>,
     private userAccessKeyService: UserAccessKeyService,
     public toastr: ToastrService
   ) {
@@ -46,7 +48,15 @@
   }
 
   ngOnInit() {
-    this.bindDialog.onClosing = () => this.resetDialog();
+    this.model = new KeyUploadDialogModel(null,
+      response => {
+        if (response.status === HTTP_STATUS_CODES.OK) {
+          this.close();
+          this.checkInfrastructureCreationProgress.emit();
+        }
+      },
+      error => this.toastr.error(error.message, 'Oops!'),
+      this.userAccessKeyService);
   }
 
   public uploadUserAccessKey_onChange($event) {
@@ -66,27 +76,7 @@
     return false;
   }
 
-  public open(params) {
-    if (!this.bindDialog.isOpened) {
-      this.model = new KeyUploadDialogModel(null,
-        response => {
-          if (response.status === HTTP_STATUS_CODES.OK) {
-            this.close();
-            this.checkInfrastructureCreationProgress.emit();
-          }
-        },
-        error => this.toastr.error(error.message, 'Oops!'),
-        this.userAccessKeyService);
-      this.bindDialog.open(params);
-    }
-  }
-
   public close() {
-    if (this.bindDialog.isOpened)
-      this.bindDialog.close();
-  }
-
-  private resetDialog(): void {
-    this.userAccessKeyUploadControl.nativeElement.value = '';
+    this.dialogRef.close();
   }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/modal.component.html b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/modal.component.html
deleted file mode 100644
index bb7bac2..0000000
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/modal.component.html
+++ /dev/null
@@ -1,42 +0,0 @@
-<!--
-  ~ 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 #modalRoot id="modalRoot" class="dialog" role="dialog" [ngClass]="{ in: isOpened, out: isHide }"
-  (keydown.esc)="closeOnEscape ? close() : 0" (click)="closeOnOutsideClick($event) ? close() : 0">
-  <div [class]="'dialog-container ' + modalClass">
-    <div class="dialog-content" tabindex="0" *ngIf="isOpened">
-      <div [ngClass]="{ 'dialog-header': isHeader,  'hidden': !isHeader }">
-        <h4 class="modal-title" *ngIf="title">{{ title }}</h4>
-        <ng-content select="modal-header"></ng-content>
-        <button *ngIf="!hideCloseButton" type="button" class="close" data-dismiss="modal"
-          [attr.aria-label]="cancelButtonLabel || 'Close'" (click)="close()">&times;</button>
-      </div>
-      <div class="dialog-body">
-        <ng-content select="modal-content"></ng-content>
-      </div>
-      <div [ngClass]="{ 'modal-footer': isFooter,  'hidden': !isFooter }">
-        <ng-content select="modal-footer"></ng-content>
-        <button mat-raised-button *ngIf="cancelButtonLabel" type="button" class="btn btn-default" data-dismiss="modal"
-          (click)="close()">{{ cancelButtonLabel }}</button>
-        <button mat-raised-button *ngIf="submitButtonLabel" type="button" class="btn btn-primary"
-          (click)="onSubmit.emit(undefined)">{{ submitButtonLabel }}</button>
-      </div>
-    </div>
-  </div>
-</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/modal.component.scss b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/modal.component.scss
deleted file mode 100644
index 8a6c09d..0000000
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/modal.component.scss
+++ /dev/null
@@ -1,399 +0,0 @@
-/*!
- * 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.
- */
-
-/** Keyframes **/
-@keyframes show {
-  from { opacity: 0; transform: translateY(-25%); }
-  20% { opacity: 0; transform: translateY(-20%); }
-  to { opacity: 1; transform: translateY(0%); }
-}
-@keyframes hide {
-  from { opacity: 1; transform: translateY(0%); }
-  35% { opacity: 0; transform: translateY(-20%)}
-  to { opacity: 0; transform: translateY(-25%); }
-}
-@keyframes showSlideSide {
-  from { opacity: 0; transform: translateX(150%); }
-  35% { opacity: 0; transform: translateX(100%); }
-  to { opacity: 1; transform: translateX(0%); }
-}
-@keyframes hideSlideSide {
-  from { opacity: 1; transform: translateX(0%); }
-  35% { opacity: 0; }
-  to { opacity: 0; transform: translateX(150%); }
-}
-
-.modal-xs { width: 375px; }
-.modal-sm { width: 525px; }
-.modal-md { width: 545px; }
-.modal-lg { width: 580px; }
-.modal-xl-s { width: 660px; }
-.modal-xl { width: 900px; }
-.modal-xxl { width: 1000px; }
-
-.backdrop {
-  position: fixed;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  z-index: 5;
-  background-color: #000;
-  transition: .3s ease-in-out;
-  opacity: .5;
-  filter: alpha(opacity=50);
-}
-
-.dialog {
-  color: #718ba6;
-  font-size: 14px;
-  position: fixed;
-  top: 0;
-  right: 0;
-  bottom: 0;
-  left: 0;
-  z-index: 10;
-  overflow: hidden;
-  -webkit-overflow-scrolling: touch;
-  justify-content: center;  
-  outline: 0;
-}
-.dialog:not(.in) {
-  visibility: hidden;
-}
-.dialog.in {
-  visibility: visible;
-  display: flex
-}
-
-.dialog.in .dialog-container {
-  animation-duration: .35s;
-  animation-fill-mode: forwards;
-  animation-name: show;
-  animation-timing-function: ease;
-}
-
-.dialog.out .dialog-container {
-  animation-duration: .35s;
-  animation-fill-mode: forwards;
-  animation-name: hide;
-  animation-timing-function: ease;
-}
-
-/* .dialog.in .dialog-container.install-libs {
-  animation-duration: .35s;
-  animation-fill-mode: forwards;
-  animation-name: showSlideSide;
-  animation-timing-function: ease;
-  width: 100%;
-}
-
-.dialog.in .dialog-container.install-libs .dialog-content {
-  height: 100vh;
-  width: 100%;
-}
-
-.dialog.out .dialog-container.install-libs {
-  animation-duration: .25s;
-  animation-fill-mode: forwards;
-  animation-name: hideSlideSide;
-  animation-timing-function: ease;
-} */
-
-.dialog.in .dialog-container.install-libraries {
-  animation-duration: .35s;
-  animation-fill-mode: forwards;
-  animation-name: showSlideSide;
-  animation-timing-function: ease;
-  width: 100%;
-  height: 100%;
-}
-
-.dialog.in .dialog-container.install-libraries .dialog-content {
-  width: 100%;
-  height: 100%;
-}
-.install-libraries .dialog-body {
-  height: calc(100% - 50px);
-}
-.install-libraries .mat-tab-body-wrapper {
-  flex-grow: 1;
-}
-
-.install-libraries .mat-tab-body {
-  display: flex !important;
-  flex-direction: column;
-}
-
-.install-libraries .mat-tab-body-content {
-  display: flex;
-  flex-direction: column;
-  flex-grow: 1;
-  height: 100%;
-}
-.install-libraries .dialog-body .content-box {
-  padding: 35px 50px 45px;
-  height: 100%;
-}
-
-.dialog.out .dialog-container.install-libraries {
-  animation-duration: .35s;
-  animation-fill-mode: forwards;
-  animation-name: hideSlideSide;
-  animation-timing-function: ease;
-}
-
-.dialog-container {
-  flex-direction: column;
-  align-items: center;
-  align-self: center;
-  list-style: none;
-  padding: 0;
-  margin: 0;
-  transition: all .35s linear .2s;
-}
-
-.dialog-content {
-  display: block;
-  position: relative;
-  background-color: #fff;
-  -webkit-background-clip: padding-box;
-  background-clip: padding-box;
-  border: 1px solid rgba(0,0,0,.2);
-  border-radius: 3px;
-  outline: 0;
-  -webkit-box-shadow: 0 3px 9px rgba(0,0,0,.5);
-  box-shadow: 0 3px 9px rgba(0,0,0,.5);
-  .danger_color {
-    padding-left: 5px;
-    font-size: 12px;
-    display: inline-block;
-    font-family: 'Open Sans', sans-serif;
-    font-weight: 300;
-    border-color: #d9534f !important;
-  }
-}
- 
-.modal-footer .btn {
-  margin-top: 0;
-}
-
-.dialog {
-  .header-white {
-    .dialog-header {
-      background: #fff;
-    }
-  }
-  .dialog-header {
-    padding-left: 30px;
-    background: #f6fafe;
-    height: 54px;
-    line-height: 54px;
-    .modal-title {
-      width: 90%;
-      margin: 0;
-      overflow: hidden;
-      white-space: nowrap;
-      text-overflow: ellipsis;
-      font-weight: 600;
-      color: #455c74;
-      font-size: 18px;
-      background: #f6fafe;
-      i {
-        vertical-align: middle;
-      }
-    }
-    .close {
-      position: absolute;
-      top: 0;
-      right: 0;
-      height: 50px;
-      width: 50px;
-      font-size: 24px;
-      border: 0;
-      background: none;
-      color: #577289;
-      outline: none;
-      cursor: pointer;
-      transition: all .45s ease-in-out;
-      &:hover {
-        color: #36afd5;
-      }
-    }
-  }
-
-  .dialog-body {
-    padding-top: 0;
-  }
-  .upload-key {
-    margin-bottom: 20px;
-    & > div > div {
-      margin-top: 5px;
-    }
-
-    .butt-file {
-      position: relative;
-      overflow: hidden;
-      margin-bottom: 10px;
-      display: inline-block;
-      color: #35afd5;
-      padding: 6px 29px 6px 23px;
-      width: 170px;
-      // font: 600 16px/1.45 'Open Sans';
-      font-style: normal;
-      font-weight: 600;
-      font-size: 16px;
-      line-height: 1.45;
-      font-family:'Open Sans', sans-serif;
-
-      text-align: center;
-      box-shadow: 0 3px 1px -2px rgba(0,0,0,.2), 0 2px 2px 0 rgba(0,0,0,.14), 0 1px 5px 0 rgba(0,0,0,.12);
-
-      .upload-icon {
-        background: url(../../../assets/img/upload-icon.png) no-repeat;
-        background-size: 100%;
-        display: inline-block;
-        width: 17px;
-        height: 17px;
-        margin-right: 8px;
-        position: relative;
-        top: 2px;
-      }
-      input[type=file] {
-        width: 100%;
-        height: 100%;
-        position: absolute;
-        top: 0;
-        right: 0;
-        min-width: 100%;
-        min-height: 100%;
-        font-size: 100px;
-        text-align: right;
-        opacity: 0;
-        outline: none;
-        background: #fff;
-        cursor: inherit;
-        display: block;
-      }
-      &:active {
-        box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
-      }
-    }
-    .butt-generate {
-      color: #35afd5;
-      width: 170px;
-    }
-  }
-  .btn-success {
-    margin-left: 40px;
-    margin-right: 2px;
-  }
-  .btn {
-    padding: 6px 15px;
-    min-width: 140px;
-    font-weight: 600;
-  }
-  a {
-    color: #35afd5;
-    text-decoration: none;
-    transition: all .45s ease-in-out;
-    &:hover {
-      color: #5faec7;
-    }
-  }
-  .info-label {
-    font-size: 16px;
-    margin-top: 20px;
-  }
-  .control-label {
-    font-weight: 600;
-    margin-top: 6px;
-  }
-  .form-group {
-    small {
-      font-size: 12px;
-      color: #9cadbe;
-      display: inline-block;
-      margin-top: 6px;
-    }
-  }
-}
-.content-box {
-  padding: 25px 30px 35px;
-}
-.detail-header {
-  border-bottom: 0;
-  width: 100%;
-  border-collapse: collapse;
-  table-layout: fixed;
-  td {
-    border: 1px solid #edf1f5;
-    text-align: center;
-    padding: 20px;
-    text-align: center !important;
-    background: #fff;
-    &:first-child {
-      background: #f6fafe;
-      font-size: 16px;
-      font-weight: 600;
-      color: #455c74;
-      text-overflow: ellipsis;
-      overflow: hidden;
-      cursor: default;
-    }
-    &.tooltip-wrap {
-      .hint-title {
-        font-size: 16px;
-        font-weight: 600;
-        color: #455c74;
-        overflow: hidden;
-        text-overflow: ellipsis;
-      }
-    }
-  }
-}
-
-.detail-info {
-  p {
-    font-weight: 400;
-    margin-bottom: 10px;
-    small {
-      font-size: 12px;
-      font-weight: 400;
-    }
-  }
-  span {
-    font-size: 14px;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    display: block;
-  }
-  .links_block {
-    padding-left: 25px;
-  }
-  .time_info {
-    margin-top: 15px;
-  }
-}
-
-.create-cluster {
-  .dialog-header {
-    padding-left: 45px !important;
-  }
-}
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/modal.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/modal.component.ts
deleted file mode 100644
index d6a1665..0000000
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/modal.component.ts
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * 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, Input, Output, EventEmitter, ElementRef, ViewChild, ViewEncapsulation } from '@angular/core';
-
-@Component({
-  selector: 'modal-dialog',
-  templateUrl: 'modal.component.html',
-  styleUrls: ['./modal.component.scss'],
-  encapsulation: ViewEncapsulation.None
-})
-
-export class ModalComponent implements OnDestroy {
-
-  isOpened: boolean = false;
-  isHeader: boolean = true;
-  isFooter: boolean = true;
-  onClosing: Function;
-  isHide: boolean;
-  clear: number;
-
-  @Input() modalClass: string;
-  @Input() title: string;
-  @Input() cancelButtonLabel: string;
-  @Input() submitButtonLabel: string;
-  @Input() hideCloseButton: boolean = false;
-  @Input() closeOnEscape: boolean = true;
-
-  @Output() onOpen = new EventEmitter(false);
-  @Output() onClose = new EventEmitter(false);
-  @Output() onSubmit = new EventEmitter(false);
-
-  @ViewChild('modalRoot') el: ElementRef;
-
-  private backdropElement: HTMLElement;
-
-  constructor() {
-    this.createBackDrop();
-  }
-
-  closeOnOutsideClick($event): boolean {
-    return ($event.target && $event.target.id === 'modalRoot');
-  }
-
-  ngOnDestroy() {
-    document.body.className = document.body.className.replace(/modal-open\b/, '');
-    if (this.backdropElement && this.backdropElement.parentNode === document.body)
-      document.body.removeChild(this.backdropElement);
-  }
-
-  public open(option: Object, ...args: any[]): void {
-    if (this.isOpened)
-      return;
-
-    if (option) {
-      for (const key in option) {
-        this[key] = option[key];
-      }
-    }
-
-    this.isOpened = true;
-    this.isHide = false;
-    this.onOpen.emit(args);
-    document.body.appendChild(this.backdropElement);
-    window.setTimeout(() => this.el.nativeElement.focus(), 0);
-    document.body.className += ' modal-open';
-  }
-
-  public close(...args: any[]): void {
-    if (!this.isOpened)
-      return;
-
-    if (this.onClosing)
-      this.onClosing();
-    this.onClose.emit(args);
-
-    this.isHide = true;
-    this.clear = window.setTimeout(() => {
-      document.body.contains(this.backdropElement) && document.body.removeChild(this.backdropElement);
-      document.body.className = document.body.className.replace(/modal-open\b/, '');
-      this.el.nativeElement.classList.remove('out');
-      this.isOpened = false;
-
-      clearTimeout(this.clear);
-    }, 300);
-
-    if (document.getElementsByClassName('dropdown open').length)
-      document.getElementsByClassName('dropdown open')[0].classList.remove('open');
-  }
-
-  private createBackDrop() {
-    this.backdropElement = document.createElement('div');
-    this.backdropElement.classList.add('backdrop');
-  }
-}
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/notification-dialog/index.ts b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/notification-dialog/index.ts
index 4daec02..7f66ebc 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/notification-dialog/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/notification-dialog/index.ts
@@ -20,14 +20,13 @@
 import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
 
-import { ModalModule } from '..';
 import { NotificationDialogComponent } from './notification-dialog.component';
 import { MaterialModule } from '../../material.module';
 
 export * from './notification-dialog.component';
 
 @NgModule({
-  imports: [CommonModule, ModalModule, MaterialModule],
+  imports: [CommonModule, MaterialModule],
   declarations: [NotificationDialogComponent],
   entryComponents: [NotificationDialogComponent],
   exports: [NotificationDialogComponent]
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 dab2f10..6469f37 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
@@ -23,45 +23,64 @@
 @Component({
   selector: 'notification-dialog',
   template: `
-  <header>
-    <h4><i class="material-icons">priority_high</i>Warning</h4>
-    <a class="ani" (click)="dialogRef.close()"><i class="material-icons">close</i></a>
-  </header>
-  <div mat-dialog-content class="content info message">
-    <div *ngIf="data.type === 'list'; else info">
-      <div *ngIf="data.template.notebook.length > 0">
-        Following notebook server<span *ngIf="data.template.notebook.length>1">s </span>
-        <span *ngFor="let item of data.template.notebook">
-          <b>{{ item.exploratory_name }}</b>
-          <span *ngIf="data.template.notebook.length > 1">, </span>
-        </span> will be stopped and all computational resources will be stopped/terminated
-      </div>
+  <div id="dialog-box">
+    <header class="dialog-header">
+      <h4 class="modal-title"><i class="material-icons">priority_high</i>Warning</h4>
+      <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+    </header>
+    <div mat-dialog-content class="content message">
+      <div *ngIf="data.type === 'list'" class="info">
+        <div *ngIf="data.template.notebook.length > 0">
+          Following notebook server<span *ngIf="data.template.notebook.length>1">s </span>
+          <span *ngFor="let item of data.template.notebook">
+            <b>{{ item.exploratory_name }}</b>
+            <span *ngIf="data.template.notebook.length > 1">, </span>
+          </span> will be stopped and all computational resources will be stopped/terminated
+        </div>
 
-      <div *ngIf="data.template.cluster.length > 0">
-        <p *ngFor="let item of data.template.cluster">
-            Computational resource<span *ngIf="data.template.cluster.length > 1">s </span>
-            <b>{{ item.computational_name }}</b> on <b>{{ item.exploratory_name }}</b>
-            will be stopped
-        </p>
+        <div *ngIf="data.template.cluster.length > 0">
+          <p *ngFor="let item of data.template.cluster">
+              Computational resource<span *ngIf="data.template.cluster.length > 1">s </span>
+              <b>{{ item.computational_name }}</b> on <b>{{ item.exploratory_name }}</b>
+              will be stopped
+          </p>
+        </div>
+        <strong>by a schedule in 15 minutes.</strong>
       </div>
-      <strong>by a schedule in 15 minutes.</strong>
+      <div *ngIf="data.type === 'message'"><span [innerHTML]="data.template"></span></div>
+      <div *ngIf="data.type === 'confirmation'" class="confirm-dialog">
+        <p>
+          <strong class="ellipsis label-name" matTooltip="{{ data.item.name }}" matTooltipPosition="above" [matTooltipDisabled]="data.item.name.length > 35">
+          {{ data.item.name }}</strong> will be {{ data.action || 'decommissioned' }}.
+        </p>
+        <p class="m-top-20"><strong>Do you want to proceed?</strong></p>
+      
+        <div class="text-center m-top-30 m-bott-10">
+          <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>
     </div>
-    <ng-template #info><span [innerHTML]="data.template"></span></ng-template>
   </div>
   `,
   styles: [`
-    .content { color: #718ba6; padding: 20px 50px; font-size: 14px; font-weight: 400 }
+    .content { color: #718ba6; padding: 20px 50px; font-size: 14px; font-weight: 400; margin: 0; }
     .info { color: #35afd5; }
+    .info .confirm-dialog { color: #607D8B; }
     header { display: flex; justify-content: space-between; color: #607D8B; }
     header h4 i { vertical-align: bottom; }
     header a i { font-size: 20px; }
     header a:hover i { color: #35afd5; cursor: pointer; }
     .plur { font-style: normal; }
+    .label-name { display: inline-block; width: 100% }
   `]
 })
 export class NotificationDialogComponent {
   constructor(
     public dialogRef: MatDialogRef<NotificationDialogComponent>,
     @Inject(MAT_DIALOG_DATA) public data: any
-  ) { }
+  ) {
+    console.log(data);
+
+  }
 }
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/progress-dialog/index.ts b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/progress-dialog/index.ts
index 8001541..f66af62 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/progress-dialog/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/progress-dialog/index.ts
@@ -19,14 +19,15 @@
 
 import { NgModule } from '@angular/core';
 import { CommonModule } from '@angular/common';
-import { ModalModule } from '..';
+
 import { ProgressDialogComponent } from './progress-dialog.component';
 
 export * from './progress-dialog.component';
 
 @NgModule({
-  imports: [CommonModule, ModalModule],
+  imports: [CommonModule],
   declarations: [ProgressDialogComponent],
+  entryComponents: [ProgressDialogComponent],
   exports: [ProgressDialogComponent],
 })
 
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/progress-dialog/progress-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/progress-dialog/progress-dialog.component.html
index 45cc7ae..726bcfb 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/progress-dialog/progress-dialog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/progress-dialog/progress-dialog.component.html
@@ -17,13 +17,14 @@
   ~ under the License.
   -->
 
-<modal-dialog #bindDialog modalClass="modal-xs progress-dialog">
-  <modal-header></modal-header>
-  <modal-content class="text-center">
+<div id="dialog-box" class="progress-dialog">
+  <header class="dialog-header header-white">
+    <button type="button" class="close" (click)="dialogRef.close()">&times;</button>
+  </header>
+  <div class="dialog-content text-center">
     <div class="content-box">
       <div><img src="assets/img/gif-spinner.gif" alt="loader"></div>
       <p class="info-label">Initial infrastructure is being created, <br/>please, wait...</p>
     </div>
-  </modal-content>
-  <modal-footer></modal-footer>
-</modal-dialog>
+  </div>
+</div>
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/progress-dialog/progress-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/progress-dialog/progress-dialog.component.ts
index 5dc200a..9e2c7ad 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/progress-dialog/progress-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/progress-dialog/progress-dialog.component.ts
@@ -17,7 +17,8 @@
  * under the License.
  */
 
-import { Component, OnInit, ViewChild, Input } from '@angular/core';
+import { Component, OnInit, Input, Inject } from '@angular/core';
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
 
 @Component({
   selector: 'progress-dialog',
@@ -27,20 +28,13 @@
 export class ProgressDialogComponent implements OnInit {
   @Input() theBoundCallback: Function;
 
-  @ViewChild('bindDialog') bindDialog;
+  constructor(
+    @Inject(MAT_DIALOG_DATA) public data: any,
+    public dialogRef: MatDialogRef<ProgressDialogComponent>,
+  ) { }
 
   ngOnInit() {
     if (this.theBoundCallback)
       this.theBoundCallback();
   }
-
-  open(params) {
-    if (!this.bindDialog.isOpened)
-      this.bindDialog.open(params);
-  }
-
-  close() {
-    if (this.bindDialog.isOpened)
-      this.bindDialog.close();
-  }
 }
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 121e255..539970a 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
@@ -21,7 +21,7 @@
 import { CommonModule } from '@angular/common';
 import { RouterModule } from '@angular/router';
 import { MaterialModule } from '../material.module';
-import { ModalModule, UploadKeyDialogModule, ProgressDialogModule, BubbleModule } from '../index';
+import { UploadKeyDialogModule, ProgressDialogModule, BubbleModule } from '../index';
 
 import { NavbarComponent } from './navbar.component';
 import { NotificationDialogModule } from '../modal-dialog/notification-dialog';
@@ -34,7 +34,6 @@
     RouterModule,
     MaterialModule,
     NotificationDialogModule,
-    ModalModule,
     UploadKeyDialogModule,
     ProgressDialogModule,
     BubbleModule
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 6c3ca0f..ceb18f0 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
@@ -17,61 +17,91 @@
   ~ under the License.
   -->
 
-<div class="nav-bar" *ngIf="isLoggedIn">
+<div class="nav-bar" [hidden]="!isLoggedIn">
   <div class="menu-area" *ngIf="healthStatus">
 
-    <button class="hamburger" [matMenuTriggerFor]="menu">
+    <button class="hamburger" (click)="collapse()">
       <span class="line"></span>
       <span class="line"></span>
       <span class="line"></span>
     </button>
 
-    <nav role="navigation">
-      <mat-menu #menu="matMenu" [overlapTrigger]="false">
-        <a class="nav-item" mat-menu-item [routerLink]="['/resources_list']" [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}">List of Resources</a>
-        <a class="nav-item" mat-menu-item [routerLink]="['/environment_management']" [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}">Environment Management</a>
-        <a *ngIf="healthStatus.billingEnabled" class="nav-item" mat-menu-item [routerLink]="['/billing_report']" [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}">Billing Report</a>
-      </mat-menu>
-    </nav>
     <a [routerLink]="['/resources_list']" class="navbar-logo">
       <img src="assets/img/logo-nav.png" alt="">
     </a>
   </div>
 
   <div class="control-area" *ngIf="healthStatus">
-    <a *ngIf="healthStatus.status" [routerLink]="['/environment_management']" class="statusbar">
+    <!-- <a *ngIf="healthStatus.status" [routerLink]="['/environment_management']" class="statusbar">
       <span class="material-icons" ngClass="{{healthStatus.status || ''}}">radio_button_checked</span>
-    </a>
-    <!-- *ngIf="metadata" -->
-    <a  class="statusbar" #info (click)="actions.toggle($event, info)">
+    </a> -->
+    <a class="statusbar" #info (click)="actions.toggle($event, info)" *ngIf="metadata">
       <span class="material-icons meta">info</span>
     </a>
     <bubble-up #actions class="list-menu" position="bottom-right">
       <div class="app-info">
-          <p>
-            <strong>Version: </strong>
-            <span class="ellipsis">{{ metadata?.version }}</span>
-          </p>
-          <p>
-            <strong>Branch: </strong>
-            <span class="ellipsis">{{ metadata?.branch }}</span>
-          </p>
-          <p>
-            <strong>Revision: </strong>
-            <span class="ellipsis commit" matTooltip="{{ metadata?.commit }}" matTooltipPosition="above">{{ metadata?.commit }}</span>
-          </p>
-          <p>
-            <a class="helper_instruction" [attr.href]="metadata?.release_notes" target="_blank">
-              <i class="material-icons">link</i>Release notes </a>
-          </p>
+        <p>
+          <strong>Version: </strong>
+          <span class="ellipsis">{{ metadata?.version }}</span>
+        </p>
+        <p>
+          <strong>Branch: </strong>
+          <span class="ellipsis">{{ metadata?.branch }}</span>
+        </p>
+        <p>
+          <strong>Revision: </strong>
+          <span class="ellipsis commit" matTooltip="{{ metadata?.commit }}"
+            matTooltipPosition="above">{{ metadata?.commit }}</span>
+        </p>
+        <p>
+          <a class="helper_instruction" [attr.href]="metadata?.release_notes" target="_blank">
+            <i class="material-icons">link</i>Release notes </a>
+        </p>
       </div>
     </bubble-up>
-    <button class="btn btn-logout" (click)="logout_btnClick()">Log out <span class="user-name">{{currentUserName}}</span></button>
+    <button class="btn btn-logout" (click)="logout_btnClick()">Log out <span
+        class="user-name">{{currentUserName}}</span></button>
   </div>
-</div>
 
-<key-upload-dialog #keyUploadModal
-  (generateUserKey)="generateUserKey($event)"
-  (checkInfrastructureCreationProgress)="checkCreationProgress($event)"
-  [primaryUploading]="true"></key-upload-dialog>
-<progress-dialog #preloaderModal></progress-dialog>
+</div>
+<mat-sidenav-container class="example-container" autosize>
+  <mat-sidenav #drawer mode="side" opened role="navigation" [style.width]="isExpanded ? '220px' : '60px'">
+    <mat-nav-list>
+      <nav>
+        <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>
+        <a class="nav-item has-children" *ngIf="healthStatus?.admin">
+          <span *ngIf="isExpanded">Administration</span>
+
+          <a class="sub-nav-item" [style.margin-left.px]="isExpanded ? '30' : '0'" [routerLink]="['/roles']"
+            [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}">
+            <span *ngIf="isExpanded; else roles">Roles</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']" [routerLinkActiveOptions]="{exact:true}">
+            <span *ngIf="isExpanded; else projects">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]="['/environment_management']" [routerLinkActive]="['active']"
+            [routerLinkActiveOptions]="{exact:true}">
+            <span *ngIf="isExpanded; else env">Environment Management</span>
+            <ng-template #env><i class="material-icons">settings</i></ng-template>
+          </a>
+        </a>
+        <a *ngIf="healthStatus?.billingEnabled" class="nav-item" [routerLink]="['/billing_report']"
+          [routerLinkActive]="['active']" [routerLinkActiveOptions]="{exact:true}">
+          <span *ngIf="isExpanded; else billing">Billing Report</span>
+          <ng-template #billing><i class="material-icons">account_balance_wallet</i></ng-template>
+        </a>
+      </nav>
+    </mat-nav-list>
+  </mat-sidenav>
+  <mat-sidenav-content id="scrolling" [style.margin-left]="isExpanded ? '220px' : '60px'">
+    <router-outlet></router-outlet>
+  </mat-sidenav-content>
+</mat-sidenav-container>
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 e941536..823bf8e 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
@@ -57,11 +57,15 @@
       }
       .ok {
         color: #81b44a;
-        &:hover { color: #618738; }
+        &:hover {
+          color: #618738;
+        }
       }
       .warning {
         color: #f7b500;
-        &:hover { color: #bd8d0a; }
+        &:hover {
+          color: #bd8d0a;
+        }
       }
       .error {
         color: #ef5c4b;
@@ -120,20 +124,26 @@
   }
 }
 a.nav-item {
+  display: block;
   position: relative;
   height: 56px;
-  padding: 5px 40px;
+  padding: 5px 10px;
   line-height: 48px;
   font-family: "Open Sans", sans-serif;
   transition: all .45s ease-in-out;
   text-decoration: none;
   font-size: 14px;
   overflow: hidden;
-  color: #577289;
+  color: #577289 !important;
   outline: none;
-  &:hover {
+  i {
+    vertical-align: middle;
+    padding-left: 8px;
+  }
+  &:not(.has-children):hover i,
+  &:not(.has-children):hover span {
     background: none !important;
-    color: #36afd5;
+    color: #36afd5 !important;
   }
   &:not(:last-child)::after {
     content: ' ';
@@ -146,11 +156,33 @@
     background: #edf1f5;
   }
   &.active {
-    color: #36afd5;
+    color: #36afd5 !important;
   }
- }
+  &.has-children {
+    height: auto;
+  }
+  .sub-nav-item {
+    display: block;
+    transition: all .45s ease-in-out;
+    i {
+      vertical-align: middle;
+      padding-left: 8px;
+    }
+    &:hover {
+      background: none !important;
+      color: #36afd5 !important;
+    }
+    &.active {
+      color: #36afd5 !important;
+    }
+  }
+}
 
-.ok, .warning, .error, .user-name, .meta {
+.ok,
+.warning,
+.error,
+.user-name,
+.meta {
   transition: all .35s ease-in-out;
 }
 
@@ -159,12 +191,12 @@
   padding: 0px;
   background: none;
   outline: none;
-  width: 56px;
+  width: 60px;
   height: 46px;
   cursor: pointer;
   border-radius: 0;
   transition: all .45s ease-in-out;
-  .line{
+  .line {
     width: 22px;
     height: 2px;
     display: block;
@@ -195,16 +227,22 @@
   }
 }
 
-.hamburger:hover .line:nth-child(1){
+.hamburger:hover .line:nth-child(1) {
   -webkit-transform: translateY(8px) translateX(-6px) rotate(45deg);
   -ms-transform: translateY(8px) translateX(-6px) rotate(45deg);
   -o-transform: translateY(8px) translateX(-6px) rotate(45deg);
   transform: translateY(8px) translateX(-6px) rotate(45deg);
 }
 
-.hamburger:hover .line:nth-child(3){
+.hamburger:hover .line:nth-child(3) {
   -webkit-transform: translateY(-4px) translateX(6px) rotate(-45deg);
   -ms-transform: translateY(-4px) translateX(6px) rotate(-45deg);
   -o-transform: translateY(-4px) translateX(6px) rotate(-45deg);
   transform: translateY(-4px) translateX(6px) rotate(-45deg);
 }
+
+mat-sidenav-content {
+  &.mat-drawer-content {
+    transition: all 0.35s ease-out;
+  }
+}
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 ef87728..af6958d 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
@@ -20,18 +20,12 @@
 import { Component, ViewEncapsulation, OnInit, OnDestroy, ViewChild } from '@angular/core';
 import { MatDialog, MatDialogRef } from '@angular/material';
 import { Subscription, timer, interval } from 'rxjs';
-import { takeWhile } from 'rxjs/operators';
 import { ToastrService } from 'ngx-toastr';
 
-import { ApplicationSecurityService,
-  HealthStatusService,
-  AppRoutingService,
-  UserAccessKeyService,
-  SchedulerService,
-  StorageService} from '../../core/services';
-import { GeneralEnvironmentStatus } from '../../management/management.model';
+import { ApplicationSecurityService, HealthStatusService, AppRoutingService, SchedulerService, StorageService } from '../../core/services';
+import { GeneralEnvironmentStatus } from '../../administration/management/management.model';
 import { DICTIONARY } from '../../../dictionary/global.dictionary';
-import { HTTP_STATUS_CODES, FileUtils } from '../../core/util';
+import { FileUtils } from '../../core/util';
 import { NotificationDialogComponent } from '../modal-dialog/notification-dialog';
 
 @Component({
@@ -43,9 +37,6 @@
 export class NavbarComponent implements OnInit, OnDestroy {
   readonly PROVIDER = DICTIONARY.cloud_provider;
 
-  private alive: boolean = false;
-  private lastStatus: number | boolean = false;
-  private readonly CHECK_ACCESS_KEY_TIMEOUT: number = 30000;
   private readonly CHECK_ACTIVE_SCHEDULE_TIMEOUT: number = 55000;
   private readonly CHECK_ACTIVE_SCHEDULE_PERIOD: number = 15;
 
@@ -53,19 +44,16 @@
   quotesLimit: number = 70;
   isLoggedIn: boolean = false;
   metadata: any;
+  isExpanded: boolean = true;
 
   healthStatus: GeneralEnvironmentStatus;
   subscriptions: Subscription = new Subscription();
 
-  @ViewChild('keyUploadModal') keyUploadDialog;
-  @ViewChild('preloaderModal') preloaderDialog;
-
   constructor(
     public toastr: ToastrService,
     private applicationSecurityService: ApplicationSecurityService,
     private appRoutingService: AppRoutingService,
     private healthStatusService: HealthStatusService,
-    private userAccessKeyService: UserAccessKeyService,
     private schedulerService: SchedulerService,
     private storage: StorageService,
     private dialog: MatDialog
@@ -75,7 +63,6 @@
     this.applicationSecurityService.loggedInStatus.subscribe(response => {
       this.subscriptions.unsubscribe();
       this.subscriptions.closed = false;
-      this.alive = false;
 
       this.isLoggedIn = response;
 
@@ -83,9 +70,7 @@
         this.subscriptions.add(this.healthStatusService.statusData.subscribe(result => {
           this.healthStatus = result;
           result.status && this.checkQuoteUsed(this.healthStatus);
-        }));
-        this.subscriptions.add(this.userAccessKeyService.accessKeyEmitter.subscribe(result => {
-          result && this.processAccessKeyStatus(result.status);
+          result.status && !result.projectAssigned && this.checkAssignment(this.healthStatus);
         }));
         this.subscriptions.add(timer(0, this.CHECK_ACTIVE_SCHEDULE_TIMEOUT).subscribe(() => this.refreshSchedulerData()));
         this.currentUserName = this.getUserName();
@@ -96,7 +81,6 @@
 
   ngOnDestroy(): void {
     this.subscriptions.unsubscribe();
-    this.alive = false;
   }
 
   getUserName(): string {
@@ -105,7 +89,6 @@
 
   logout_btnClick(): void {
     this.healthStatusService.resetStatusValue();
-    this.userAccessKeyService.resetUserAccessKey();
     this.applicationSecurityService.logout().subscribe(
       () => {
         this.appRoutingService.redirectToLoginPage();
@@ -114,9 +97,13 @@
       error => console.error(error));
   }
 
+  collapse() {
+    this.isExpanded = !this.isExpanded;
+  }
+
   public emitQuotes(alert, user_quota?, total_quota?): void {
     const dialogRef: MatDialogRef<NotificationDialogComponent> = this.dialog.open(NotificationDialogComponent, {
-      data: { template: this.selectQuotesAlert(alert, user_quota, total_quota), type: 'message' },
+      data: { template: this.selectAlert(alert, user_quota, total_quota), type: 'message' },
       width: '550px'
     });
     dialogRef.afterClosed().subscribe(() => {
@@ -124,21 +111,6 @@
     });
   }
 
-  public generateUserKey($event): void {
-    console.log('generate key', $event);
-    this.userAccessKeyService.generateAccessKey().subscribe(
-      data => {
-        FileUtils.downloadFile(data);
-        this.userAccessKeyService.initialUserAccessKeyCheck();
-      }, error => {
-        this.toastr.error(error.message || 'Access key generation failed!', 'Oops!');
-      });
-  }
-
-  public checkCreationProgress($event): void {
-    this.userAccessKeyService.initialUserAccessKeyCheck();
-  }
-
   private checkQuoteUsed(params): void {
     if (!this.storage.getBillingQuoteUsed() && params) {
       let checkQuotaAlert = '';
@@ -153,50 +125,27 @@
     }
   }
 
-  private processAccessKeyStatus(status: number): void {
-    if (status === HTTP_STATUS_CODES.NOT_FOUND || status === HTTP_STATUS_CODES.INTERNAL_SERVER_ERROR) {
-      this.preloaderDialog.bindDialog.isOpened && this.preloaderDialog.close();
-      this.keyUploadDialog.open({ isFooter: false });
-      this.alive = false;
-      this.lastStatus = status;
-    } else if (status === HTTP_STATUS_CODES.ACCEPTED) {
-      !this.preloaderDialog.bindDialog.isOpened && this.preloaderDialog.open({ isHeader: false, isFooter: false });
-
-      if (!this.alive) {
-        this.alive = true;
-        this.subscriptions.add(
-          interval(this.CHECK_ACCESS_KEY_TIMEOUT)
-            .pipe(takeWhile(() => this.alive))
-            .subscribe(() => this.userAccessKeyService.initialUserAccessKeyCheck()));
-      }
-      this.lastStatus = status;
-    } else if (status === HTTP_STATUS_CODES.OK) {
-      if (this.lastStatus) {
-        this.userAccessKeyService.emitActionOnKeyUploadComplete();
-        this.lastStatus = false;
-      }
-      this.alive = false;
-      this.preloaderDialog.close();
-      this.keyUploadDialog.close();
-    }
+  private checkAssignment(params): void {
+    if (this.dialog.openDialogs.length > 0) return;
+    this.emitQuotes('permissions');
   }
 
   private refreshSchedulerData(): void {
-      this.schedulerService.getActiveSchcedulersData(this.CHECK_ACTIVE_SCHEDULE_PERIOD).subscribe((list: Array<any>) => {
-        if (list.length) {
-          if (this.dialog.openDialogs.length > 0 || this.dialog.openDialogs.length > 0) return;
-          const filteredData = this.groupSchedulerData(list);
-          const dialogRef: MatDialogRef<NotificationDialogComponent> = this.dialog.open(NotificationDialogComponent, {
-            data: { template: filteredData, type: 'list' },
-            width: '550px'
-          });
-        }
+    this.schedulerService.getActiveSchcedulersData(this.CHECK_ACTIVE_SCHEDULE_PERIOD).subscribe((list: Array<any>) => {
+      if (list.length) {
+        if (this.dialog.openDialogs.length > 0) return;
+        const filteredData = this.groupSchedulerData(list);
+        this.dialog.open(NotificationDialogComponent, {
+          data: { template: filteredData, type: 'list' },
+          width: '550px'
+        });
+      }
     });
   }
 
   private groupSchedulerData(sheduler_data) {
     const memo = { notebook: [], cluster: [] };
-    sheduler_data.map(item =>  !item.computational_name ? memo.notebook.push(item) : memo.cluster.push(item));
+    sheduler_data.map(item => !item.computational_name ? memo.notebook.push(item) : memo.cluster.push(item));
     memo.cluster = memo.cluster.filter(el => !memo.notebook.some(elm => el.exploratory_name === elm.exploratory_name));
     return memo;
   }
@@ -204,27 +153,33 @@
   public checkVersionData(): void {
     this.healthStatusService.getAppMetaData().subscribe(
       result => this.metadata = result || null,
-      error => this.toastr.error('Metadata loading failed!', 'Oops!'));
+      error => {
+        console.log('Metadata loading failed!');
+        // this.toastr.error('Metadata loading failed!', 'Oops!');
+      });
   }
 
-  private selectQuotesAlert(type: string, user_quota?: number, total_quota?: number): string {
+  private selectAlert(type: string, user_quota?: number, total_quota?: number): string {
     const alerts = {
-      user_exceed: `Dear <b>${ this.currentUserName }</b>,<br />
+      user_exceed: `Dear <b>${this.currentUserName}</b>,<br />
           DLab cloud infrastructure usage quota associated with your user has been exceeded.
           All your analytical environment will be stopped. To proceed working with environment,
           request increase of user quota from DLab administrator.`,
-      total_exceed: `Dear <b>${ this.currentUserName }</b>,<br />
+      total_exceed: `Dear <b>${this.currentUserName}</b>,<br />
           DLab cloud infrastructure usage quota has been exceeded.
           All your analytical environment will be stopped. To proceed working with environment,
           request increase application quota from DLab administrator.`,
-      user_quota: `Dear <b>${ this.currentUserName }</b>,<br />
+      user_quota: `Dear <b>${this.currentUserName}</b>,<br />
           Cloud infrastructure usage quota associated with your user has been used for <b>${user_quota}%</b>.
           Once quota is depleted all your analytical environment will be stopped.
           To proceed working with environment you'll have to request increase of user quota from DLab administrator.`,
-      total_quota: `Dear <b>${ this.currentUserName }</b>,<br />
+      total_quota: `Dear <b>${this.currentUserName}</b>,<br />
           DLab cloud infrastructure usage quota has been used for <b>${total_quota}%</b>.
           Once quota is depleted all your analytical environment will be stopped.
-          To proceed working with environment you'll have to request increase of user quota from DLab administrator. `
+          To proceed working with environment you'll have to request increase of user quota from DLab administrator. `,
+      permissions: `Dear <b>${this.currentUserName}</b>,<br />
+          Currently, you are not assigned to any project. To start working with the environment
+          request permission from DLab administrator.`
     };
 
     return alerts[type];
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
new file mode 100644
index 0000000..46aef3b
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/assets/styles/_dialogs.scss
@@ -0,0 +1,294 @@
+/*!
+ * 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 '_variables.scss';
+
+.modal-xs {
+  width: 375px;
+}
+
+.modal-sm {
+  width: 525px;
+}
+
+.modal-md {
+  width: 545px;
+}
+
+.modal-lg {
+  width: 580px;
+}
+
+.modal-xl-s {
+  width: 660px;
+}
+
+.modal-xl {
+  width: 900px;
+}
+
+.modal-xxl {
+  width: 1000px;
+}
+
+.modal-fullscreen {
+  width: 100vw;
+  height: 100vh;
+}
+
+mat-dialog-container {
+  overflow-x: hidden;
+
+  &.mat-dialog-container {
+    padding: 0;
+    border-radius: 0;
+
+    #dialog-box {
+      color: $modal-text-color;
+
+      .dialog-header {
+        padding-left: 30px;
+        background: $modal-header-color;
+        height: 50px;
+        line-height: 50px;
+        position: relative;
+
+        .modal-title {
+          width: 90%;
+          margin: 0;
+          overflow: hidden;
+          white-space: nowrap;
+          text-overflow: ellipsis;
+          font-weight: 600;
+          color: #455c74;
+          font-size: 18px;
+          background: $modal-header-color;
+
+          i {
+            vertical-align: middle;
+          }
+        }
+
+        .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 .45s ease-in-out;
+
+          &:hover {
+            color: #36afd5;
+          }
+        }
+
+        &.header-white {
+          background: #fff;
+        }
+      }
+
+      .dialog-body {
+        padding-top: 0;
+      }
+
+      .upload-key {
+        margin-bottom: 20px;
+
+        &>div>div {
+          margin-top: 5px;
+        }
+
+        .butt-generate {
+          color: #35afd5;
+          width: 170px;
+        }
+      }
+
+      .btn-success {
+        margin-left: 40px;
+        margin-right: 2px;
+      }
+
+      .btn {
+        padding: 6px 15px;
+        min-width: 140px;
+        font-weight: 600;
+      }
+
+      a {
+        color: #35afd5;
+        text-decoration: none;
+        transition: all .45s ease-in-out;
+
+        &:hover {
+          color: #5faec7;
+        }
+      }
+
+      .info-label {
+        font-size: 15px;
+        margin-top: 20px;
+      }
+
+      .control-label {
+        font-weight: 600;
+        margin-top: 6px;
+      }
+
+      .form-group {
+        small {
+          font-size: 12px;
+          color: #9cadbe;
+          display: inline-block;
+          margin-top: 6px;
+        }
+      }
+    }
+  }
+}
+
+.content-box {
+  padding: 25px 30px 35px;
+}
+
+.butt-file {
+  position: relative;
+  overflow: hidden;
+  margin-bottom: 10px;
+  display: inline-block;
+  color: #35afd5;
+  padding: 6px 29px 6px 23px;
+  width: 170px;
+  // font: 600 16px/1.45 'Open Sans';
+  font-style: normal;
+  font-weight: 600;
+  font-size: 16px;
+  line-height: 1.45;
+  font-family: 'Open Sans', sans-serif;
+
+  text-align: center;
+  box-shadow: 0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12);
+
+  .upload-icon {
+    background: url(/../../assets/img/upload-icon.png) no-repeat;
+    background-size: 100%;
+    display: inline-block;
+    width: 17px;
+    height: 17px;
+    margin-right: 8px;
+    position: relative;
+    top: 2px;
+  }
+
+  input[type=file] {
+    width: 100%;
+    height: 100%;
+    position: absolute;
+    top: 0;
+    right: 0;
+    min-width: 100%;
+    min-height: 100%;
+    font-size: 100px;
+    text-align: right;
+    opacity: 0;
+    outline: none;
+    background: #fff;
+    cursor: inherit;
+    display: block;
+  }
+
+  &:active {
+    box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
+  }
+}
+
+.detail-header {
+  border-bottom: 0;
+  width: 100%;
+  border-collapse: collapse;
+  table-layout: fixed;
+
+  td {
+    border: 1px solid #edf1f5;
+    text-align: center;
+    padding: 20px;
+    text-align: center !important;
+    background: #fff;
+
+    &:first-child {
+      background: #f6fafe;
+      font-size: 16px;
+      font-weight: 600;
+      color: #455c74;
+      text-overflow: ellipsis;
+      overflow: hidden;
+      cursor: default;
+    }
+
+    &.tooltip-wrap {
+      .hint-title {
+        font-size: 16px;
+        font-weight: 600;
+        color: #455c74;
+        overflow: hidden;
+        text-overflow: ellipsis;
+      }
+    }
+  }
+}
+
+.detail-info {
+  p {
+    font-weight: 400;
+    margin-bottom: 10px;
+
+    small {
+      font-size: 12px;
+      font-weight: 400;
+    }
+  }
+
+  span {
+    font-size: 14px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    display: block;
+  }
+
+  .links_block {
+    padding-left: 25px;
+  }
+
+  .time_info {
+    margin-top: 15px;
+  }
+}
+
+.create-cluster {
+  .dialog-header {
+    padding-left: 45px !important;
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/assets/styles/_general.scss b/services/self-service/src/main/resources/webapp/src/assets/styles/_general.scss
index 77278ca..8a3250e 100644
--- a/services/self-service/src/main/resources/webapp/src/assets/styles/_general.scss
+++ b/services/self-service/src/main/resources/webapp/src/assets/styles/_general.scss
@@ -17,9 +17,10 @@
  * under the License.
  */
 
+html, body { height: 100%; }
 body {
   font-family: 'Open Sans', sans-serif;
-  font-size: 16px;
+  font-size: 15px;
   overflow-x: hidden;
   font-weight: 300;
 }
@@ -44,7 +45,7 @@
 textarea {
   width: 100%;
   height: 36px;
-  padding: 0 20px;
+  padding: 0 10px;
   color: #455c74;
   color: #6e7ca0;
   border: 1px solid transparent;
@@ -83,6 +84,7 @@
   display: flex;
   flex-flow: row wrap;
   padding-bottom: 20px;
+  position: relative;
 }
 .row-wrap {
   padding-bottom: 0;
@@ -99,6 +101,7 @@
   font-weight: 600;
   align-self: center;
   text-align: left;
+  font-family: 'Open Sans', sans-serif;
 }
 .control-group .control {
   width: 65%;
@@ -153,4 +156,13 @@
     padding-right: 5px;
     overflow: hidden;
   }
+}
+
+.icon-label {
+  display: inline-block;
+  width: 30px;
+  text-align: center;
+  vertical-align: middle;
+  color: #35afd5;
+  line-height: 26px;
 }
\ No newline at end of file
diff --git a/services/self-service/src/main/resources/webapp/src/assets/styles/_reset.scss b/services/self-service/src/main/resources/webapp/src/assets/styles/_reset.scss
index 1773d70..8875e14 100644
--- a/services/self-service/src/main/resources/webapp/src/assets/styles/_reset.scss
+++ b/services/self-service/src/main/resources/webapp/src/assets/styles/_reset.scss
@@ -20,7 +20,7 @@
 * {
   box-sizing: border-box;
   margin: 0;
-	padding: 0;
+  padding: 0;
 }
 
 body {
@@ -28,21 +28,36 @@
 }
 
 /* HTML5 display-role reset for older browsers */
-article, aside, details, figcaption, figure,
-footer, header, hgroup, menu, nav, section {
+article,
+aside,
+details,
+figcaption,
+figure,
+footer,
+header,
+hgroup,
+menu,
+nav,
+section {
   display: block;
 }
 
-ol, ul {
-	list-style: none;
+ol,
+ul {
+  list-style: none;
+}
+
+a {
+  text-decoration: none
 }
 
 table {
-	border-collapse: collapse;
-	border-spacing: 0;
+  border-collapse: collapse;
+  border-spacing: 0;
 }
 
-[hidden], .hidden {
+[hidden],
+.hidden {
   display: none !important;
 }
 
@@ -83,6 +98,7 @@
 }
 
 input {
+
   &::-ms-clear,
   &::-ms-reveal {
     display: none;
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 df0b5db..9c1621c 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
@@ -21,19 +21,20 @@
 .mat-raised-button {
   &.butt {
     width: 160px;
-    height: 35px;
     padding: 0 20px;
     border-radius: 0;
     font-style: normal;
     font-weight: 600;
-    font-size: 16px;
+    font-size: 15px;
     font-family: 'Open Sans', sans-serif;
     color: #577289;
+
     i {
       margin: 0 5px 0 0;
       font-size: 20px;
       vertical-align: sub;
     }
+
     span {
       i {
         margin: 0 5px 0 0;
@@ -41,21 +42,34 @@
         vertical-align: sub;
       }
     }
+
     &.mini {
       width: 80px;
     }
+
     &.action {
       width: 140px;
     }
+
     &.butt-success {
       background-color: #49af38;
       margin-left: 25px;
       color: #fff;
+
       &.mini {
         margin-left: 5px;
         width: 80px;
       }
     }
+
+    &.butt-create {
+      color: #35afd5;
+
+      &:disabled {
+        color: #577289 !important;
+      }
+    }
+
     &:disabled {
       cursor: not-allowed;
       opacity: 0.6;
@@ -63,6 +77,78 @@
   }
 }
 
+.selector-wrapper {
+  display: flex;
+  align-self: center;
+  width: 100%;
+  height: 36px;
+  padding-left: 10px;
+  font-family: 'Open Sans', sans-serif;
+  font-size: 15px;
+  font-weight: 300;
+  box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12);
+
+  mat-form-field {
+    width: 100%;
+
+    .mat-form-field-wrapper {
+      padding-bottom: 0;
+    }
+
+    .mat-icon {
+      font-size: 20px;
+    }
+
+    .caret {
+      width: 40px;
+      height: 40px;
+      color: #4ab8dc;
+      border: none;
+      border-left: 1px solid #ececec;
+      background-color: #fff;
+      position: absolute;
+      right: 0;
+      top: 0px;
+      cursor: pointer;
+
+      &.not-allowed {
+        background-color: #dcdcdc;
+      }
+    }
+  }
+}
+
+.multiple-select {
+  border-bottom: 1px solid #dedbdb;
+  padding: 0;
+
+  a {
+    display: inline-block;
+    width: 50%;
+    padding: 0 15px;
+    text-align: center;
+    vertical-align: middle;
+    color: #575757;
+    cursor: pointer;
+
+    i {
+      vertical-align: sub;
+      font-size: 20px;
+    }
+
+    &:hover {
+      color: #4eaf3e;
+      background: #f9fafb;
+    }
+
+    &.deselect {
+      &:hover {
+        color: #f1696e;
+      }
+    }
+  }
+}
+
 .mat-button-focus-overlay {
   background-color: rgba(255, 0, 0, 0) !important;
 }
@@ -70,38 +156,50 @@
 .mat-button-ripple.mat-button-ripple-round.mat-ripple {
   border-radius: 0;
 }
+
 .ticker-wrap .mat-button-ripple.mat-button-ripple-round.mat-ripple {
   border-radius: 50%;
 }
 
 .mat-option {
   font-family: 'Open Sans', sans-serif;
+
+  .mat-option-text {
+    color: #607D8B;
+    font-size: 15px;
+  }
 }
 
 .mat-option.mat-selected {
   color: #35afd5 !important;
 }
+
 /*.mat-input-placeholder.mat-focused, */
 .mat-input-underline .mat-input-ripple,
 .mat-form-field-underline .mat-form-field-ripple,
 .mat-select-underline .mat-input-underline {
   background-color: #35afd5 !important;
 }
+
 .mat-input-placeholder.mat-focused,
 .mat-select:focus:not(.mat-select-disabled) .mat-select-trigger,
 .mat-select:focus:not(.mat-select-disabled) .mat-select-arrow,
 .mat-select:focus:not(.mat-select-disabled) .mat-select-underline {
   color: #35afd5 !important;
 }
+
 .mat-select:focus:not(.mat-select-disabled) .mat-select-underline {
   background-color: #35afd5 !important;
 }
+
 .mat-select-placeholder {
   font-size: 14px;
 }
+
 .mat-input-placeholder {
   font-weight: 400;
 }
+
 .mat-datepicker-toggle-active {
   color: #2dadd7;
 }
@@ -113,8 +211,7 @@
   height: 34px;
 }
 
-.backup-dialog span.mat-slide-toggle-content,
-.scheduler-dialog span.mat-slide-toggle-content {
+span.mat-slide-toggle-content {
   // font: 100 16px/24px 'Open Sans', sans-serif;
   font-style: normal;
   font-weight: 100;
@@ -122,32 +219,31 @@
   line-height: 24px;
   font-family: 'Open Sans', sans-serif;
 }
+
 .backup-dialog .mat-slide-toggle,
 .scheduler-dialog .mat-slide-toggle {
   width: 100%;
 }
-.backup-dialog .mat-slide-toggle-label-before .mat-slide-toggle-label {
+
+#backup-options .hold-block mat-slide-toggle {
+  display: initial;
+}
+
+#backup-options .hold-block mat-slide-toggle .mat-slide-toggle-label {
   justify-content: space-between;
 }
+
 .scheduler-dialog .mat-slide-toggle-label-before .mat-slide-toggle-label {
   justify-content: flex-end;
 }
 
-.backup-dialog
-  .mat-slide-toggle.mat-checked:not(.mat-disabled)
-  .mat-slide-toggle-thumb,
-.scheduler-dialog
-  .mat-slide-toggle.mat-checked:not(.mat-disabled)
-  .mat-slide-toggle-thumb {
+.mat-slide-toggle.mat-checked:not(.mat-disabled) .mat-slide-toggle-thumb,
+.scheduler-dialog .mat-slide-toggle.mat-checked:not(.mat-disabled) .mat-slide-toggle-thumb {
   background-color: #36afd5;
 }
 
-.backup-dialog
-  .mat-slide-toggle.mat-checked:not(.mat-disabled)
-  .mat-slide-toggle-bar,
-.scheduler-dialog
-  .mat-slide-toggle.mat-checked:not(.mat-disabled)
-  .mat-slide-toggle-bar {
+.mat-slide-toggle.mat-checked:not(.mat-disabled) .mat-slide-toggle-bar,
+.scheduler-dialog .mat-slide-toggle.mat-checked:not(.mat-disabled) .mat-slide-toggle-bar {
   background-color: rgba(54, 175, 213, 0.3);
 }
 
@@ -157,6 +253,10 @@
   background-color: #36afd5;
 }
 
+.mat-slide-toggle.mat-checked .mat-ripple-element {
+  background-color: #36afd5;
+}
+
 .mat-calendar-body-cell-content.mat-calendar-body-selected {
   background: #36afd5;
 }
@@ -169,54 +269,73 @@
   white-space: pre-line !important;
   word-break: break-all;
 }
-.manage-roles-dialog {
+
+.manage-roles,
+.project-form,
+.selection {
   .mat-form-field {
     width: 100%;
   }
+
   .inner-step {
     .mat-select-value {
       width: 96%;
     }
   }
+
   .list-selected {
     .mat-chip-list {
       .mat-chip-list-wrapper {
         overflow-y: auto;
-        max-height: 115px;
+        max-height: 130px;
       }
     }
   }
+
   .mat-reset {
     .mat-form-field-type-mat-select:not(.mat-form-field-disabled) {
       .mat-form-field-flex {
-        line-height: 20px;
+        // line-height: 1;
+        // padding-top: 2px;
       }
     }
+
     .mat-form-field {
       .mat-form-field-wrapper {
         overflow: hidden;
+
         .mat-form-field-infix {
           width: 275px;
           border: 0;
           font-family: 'Open Sans', sans-serif;
-          font-size: 16px;
+          font-size: 15px;
           font-weight: 300;
+          padding-top: 10px;
+
           .mat-select-value-text {
             span {
               color: #607d8b;
             }
           }
         }
+
         .mat-form-field-underline {
           display: none;
         }
+
         .mat-select-arrow {
           color: transparent !important;
         }
+
         .mat-form-field-label {
           padding-top: 0;
           color: #607d8b;
+
+          mat-label {
+            vertical-align: middle;
+          }
         }
+
         .mat-select {
           &:focus {
             .mat-input-underline {
@@ -224,6 +343,7 @@
                 background-color: transparent !important;
               }
             }
+
             &:not(.mat-select-disabled) {
               .mat-select-arrow {
                 color: transparent;
@@ -232,23 +352,29 @@
           }
         }
       }
+
       .mat-input-wrapper.mat-form-field-wrapper .mat-form-field-underline {
         display: none;
       }
     }
   }
+
   .mat-form-field-type-mat-chip-list {
     width: 100%;
   }
+
   .mat-step-header {
     .mat-step-icon {
       background-color: #36afd5;
     }
   }
+
   .mat-chip {
     background-color: rgba(47, 174, 215, 0.2) !important;
     color: #687e96;
+    max-width: 385px !important;
   }
+
   .roles {
     .selector-wrapper-edit {
       .mat-select-value {
@@ -258,6 +384,102 @@
   }
 }
 
+mat-horizontal-stepper {
+  .mat-step-header {
+    .mat-step-icon {
+      background-color: #36afd5;
+    }
+
+    .mat-step-label {
+      font-family: 'Open Sans', sans-serif;
+      font-size: 15px;
+      font-weight: 300;
+    }
+  }
+
+  &.stepper {
+    margin-top: 10px;
+
+    .inner-step {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      padding: 5px;
+
+      input {
+        width: 100%;
+        align-self: center;
+      }
+
+      .caret {
+        i {
+          margin-top: 3px;
+        }
+      }
+    }
+
+    .text-center {
+      button {
+        &:not(:last-child) {
+          margin-right: 5px;
+        }
+      }
+    }
+
+    &.roles {
+      height: 190px;
+      flex-direction: column;
+      text-align: center;
+
+      .inner-step {
+        height: 70px;
+
+        input {
+          width: 490px;
+        }
+      }
+    }
+  }
+}
+
+.multiple-select {
+  border-bottom: 1px solid #dedbdb;
+  padding: 0 !important;
+
+  a {
+    display: inline-block;
+    width: 50%;
+    padding: 0 15px;
+    vertical-align: middle;
+    color: #575757;
+    cursor: pointer;
+
+    i {
+      vertical-align: sub;
+      font-size: 20px;
+    }
+
+    &:hover {
+      color: #4eaf3e;
+      background: #f9fafb;
+    }
+
+    &.deselect {
+      &:hover {
+        color: #f1696e;
+      }
+    }
+  }
+
+  mat-pseudo-checkbox {
+    display: none;
+  }
+
+  &.empty {
+    margin-left: 15px;
+  }
+}
+
 .dashboard_table {
   &.reporting {
     .dropdown-multiselect {
@@ -283,8 +505,11 @@
 
 .error-modalbox {
   overflow: hidden;
+
   .mat-dialog-container {
+    overflow-x: hidden;
     padding: 0;
+
     .content {
       color: #718ba6;
       padding: 20px 0;
@@ -293,6 +518,7 @@
       text-align: center;
       margin: 0;
     }
+
     .dialog-header {
       position: relative;
       top: 0;
@@ -301,14 +527,17 @@
       height: 54px;
       line-height: 54px;
     }
+
     .dialog-header h4 {
       color: #455c74;
       font-size: 18px;
       font-weight: 600;
+
       i {
         vertical-align: sub;
       }
     }
+
     .close {
       position: absolute;
       top: 0;
@@ -323,11 +552,58 @@
       cursor: pointer;
       transition: all 0.45s ease-in-out;
     }
+
     .close:hover {
       color: #36afd5;
     }
+
     .text-center button {
       margin-bottom: 25px;
     }
   }
 }
+
+.mat-table {
+  th.mat-header-cell {
+    font-size: 15px;
+    font-family: 'Open Sans', sans-serif;
+    font-weight: 600;
+    color: #607D8B;
+  }
+
+  .mat-cell {
+    word-break: break-all;
+    vertical-align: top;
+    padding: 10px 5px;
+  }
+
+  tr.mat-footer-row {
+    font-weight: bold;
+  }
+
+  // .mat-table-sticky {
+  //   border-top: 1px solid #e0e0e0;
+  // }
+}
+
+mat-tab-group.mat-tab-group {
+  height: 100%;
+
+  .mat-tab-body-wrapper {
+    height: 100%;
+  }
+}
+
+mat-divider.mat-divider {
+  margin: 10px 0;
+}
+
+mat-progress-bar {
+  .mat-progress-bar-fill::after {
+    background-color: #00BCD4;
+  }
+
+  .mat-progress-bar-buffer {
+    background-color: #baf0f7;
+  }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/create-resource.model.ts b/services/self-service/src/main/resources/webapp/src/assets/styles/_variables.scss
similarity index 87%
rename from services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/create-resource.model.ts
rename to services/self-service/src/main/resources/webapp/src/assets/styles/_variables.scss
index 9209b09..538128b 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/create-resource.model.ts
+++ b/services/self-service/src/main/resources/webapp/src/assets/styles/_variables.scss
@@ -1,4 +1,4 @@
-/*
+/*!
  * 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
@@ -17,9 +17,7 @@
  * under the License.
  */
 
-export class CreateResourceModel {
-  constructor(
-    public name: string,
-    public count: string
-  ) { }
-}
+$modal-text-color: #718aa5;
+$modal-header-color: #f6fafe;
+
+$brand-color: #4ab8dc;
\ No newline at end of file
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 c02e0ef..5b72b0f 100644
--- a/services/self-service/src/main/resources/webapp/src/styles.scss
+++ b/services/self-service/src/main/resources/webapp/src/styles.scss
@@ -17,14 +17,15 @@
  * under the License.
  */
 
-@import '~@angular/material/prebuilt-themes/deeppurple-amber.css';
+// @import '~@angular/material/prebuilt-themes/deeppurple-amber.css';
 
 @import './assets/fonts/Material_Icons/material-icons.css';
 @import './assets/fonts/Open_Sans/open-sans.css';
 
-@import './assets/styles/_reset.scss';
-@import './assets/styles/_general.scss';
-@import './assets/styles/_theme.scss';
+@import '_reset.scss';
+@import '_general.scss';
+@import '_theme.scss';
+@import '_dialogs.scss';
 
 .mat-tab-label {
   font-family: 'Open Sans', sans-serif !important;
@@ -32,8 +33,8 @@
 }
 
 .install-libraries .mat-ink-bar,
-.manage-ungit .mat-ink-bar {
-  background-color: #35afd5 !important;
+.tabs .mat-ink-bar,
+.tabs .mat-tab-label {
   width: 50% !important;
 }
 
@@ -46,17 +47,23 @@
   background-color: rgba(53, 175, 213, 0.11) !important;
   color: #577289;
 }
+
 .mat-tab-header-pagination.mat-tab-header-pagination-after,
 .mat-tab-header-pagination.mat-tab-header-pagination-before {
   display: none !important;
 }
 
+.mat-drawer-container {
+  height: calc(100% - 48px);
+}
+
 mat-chip.mat-chip {
   outline: none;
   color: #758ea8;
   font-size: 14px;
   padding: 8px 18px;
 }
+
 mat-chip.mat-chip a {
   display: inline-block;
   width: 12px;
@@ -85,17 +92,20 @@
   margin-right: 15px;
   float: right;
 }
+
 .rotate {
   -webkit-animation: spin 2s linear infinite;
   animation: spin 2s linear infinite;
 }
+
 .status {
   text-transform: capitalize;
 }
 
 .running,
 .starting,
-.installed {
+.installed,
+.active {
   color: #49af38;
 }
 
@@ -115,9 +125,13 @@
 
 .terminated,
 .terminating,
-.failed,
+.failed {
+  color: #f1696e;
+}
+
 .error {
   color: #f1696e;
+  font-size: 12px;
 }
 
 .not-allowed {
@@ -127,12 +141,18 @@
   pointer-events: none;
 }
 
+.not-active {
+  cursor: not-allowed !important;
+  opacity: .6;
+}
+
 .message {
   padding: 40px 20px;
   text-align: center;
 }
+
 .info {
-  font-size: 16px;
+  font-size: 15px;
   font-weight: 300;
   color: #35afd5;
 }
@@ -155,6 +175,7 @@
   0% {
     -webkit-transform: rotate(0deg);
   }
+
   100% {
     -webkit-transform: rotate(360deg);
   }
@@ -164,6 +185,7 @@
   0% {
     transform: rotate(0deg);
   }
+
   100% {
     transform: rotate(360deg);
   }
@@ -223,10 +245,12 @@
 }
 
 /* IE can just show/hide with no transition */
-@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
+@media all and (-ms-high-contrast: none),
+(-ms-high-contrast: active) {
   .tooltip-wrap .tooltip {
     display: none;
   }
+
   .tooltip-wrap:hover .tooltip {
     display: block;
   }
@@ -247,38 +271,63 @@
 .text-center {
   text-align: center !important;
 }
+
 .text-right {
   text-align: right;
 }
+
 .m-top-10 {
   margin-top: 10px;
 }
+
 .m-top-15 {
   margin-top: 15px;
 }
+
 .m-top-20 {
   margin-top: 20px;
 }
+
 .m-top-30 {
   margin-top: 30px;
 }
+
 .m-bott-10 {
   margin-bottom: 10px;
 }
+
 .m-top-10p {
   margin-top: 10%;
 }
 
+.ml-10 {
+  margin-left: 10px;
+}
+
 .full-height {
   height: 100%;
 }
+
 .ani {
   transition: all .35s ease-in-out;
 }
 
+.empty-box {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  justify-content: center;
+  height: 100%;
+
+  .content {
+    text-align: center;
+  }
+}
+
 #scrolling::-webkit-scrollbar,
 .list-selected mat-chip-list .mat-chip-list-wrapper::-webkit-scrollbar {
-  width: 6px;
+  width: 5px;
+  height: 5px;
 }
 
 #scrolling::-webkit-scrollbar-track,
@@ -303,6 +352,7 @@
   color: #fff;
   background: #e2747d;
   word-break: break-word;
+
   span {
     position: absolute;
     top: -12px;
@@ -322,20 +372,22 @@
   white-space: nowrap;
   overflow: hidden;
 }
+
 .capitalize {
   text-transform: capitalize;
 }
 
 .overlay-container {
   #toast-container {
-    > div.toast {
-      box-shadow: 0 3px 1px -2px rgba(0,0,0,.2), 0 2px 2px 0 rgba(0,0,0,.14), 0 1px 5px 0 rgba(0,0,0,.12);
+    >div.toast {
+      box-shadow: 0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12);
       border-radius: 2px;
       background-color: #fff;
       padding: 12px 20px;
       overflow: inherit;
       margin: 0 0 15px;
       font-size: 14px;
+
       &::before {
         position: absolute;
         left: -15px;
@@ -347,32 +399,40 @@
         padding: 7px;
         box-sizing: border-box;
         border-radius: 50%;
-        box-shadow: 0 3px 1px -2px rgba(0,0,0,.2), 0 2px 2px 0 rgba(0,0,0,.14), 0 1px 5px 0 rgba(0,0,0,.12);
+        box-shadow: 0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12);
       }
+
       &.toast-success {
         background-image: none;
         color: #49af38;
+
         &::before {
           content: "done";
         }
       }
+
       &.toast-error {
         background-image: none;
         color: #e2747d;
+
         &::before {
           content: "priority_high";
         }
       }
+
       &.toast-info {
         background-image: none;
         color: #35afd5;
+
         &::before {
           content: "priority_high";
         }
       }
+
       &.toast-warning {
         background-image: none;
         color: #f7b500;
+
         &::before {
           content: "priority_high";
         }
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/ExploratoryResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/ExploratoryResourceTest.java
index 2fa4c45..25cc0b7 100644
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/ExploratoryResourceTest.java
+++ b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/ExploratoryResourceTest.java
@@ -63,7 +63,8 @@
 
 	@Test
 	public void create() {
-		when(exploratoryService.create(any(UserInfo.class), any(Exploratory.class))).thenReturn("someUuid");
+		when(exploratoryService.create(any(UserInfo.class), any(Exploratory.class), anyString())).thenReturn(
+				"someUuid");
 		final Response response = resources.getJerseyTest()
 				.target("/infrastructure_provision/exploratory_environment")
 				.request()
@@ -74,14 +75,16 @@
 		assertEquals("someUuid", response.readEntity(String.class));
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(exploratoryService).create(getUserInfo(), getExploratory(getExploratoryCreateFormDTO()));
+		verify(exploratoryService).create(refEq(getUserInfo()), refEq(getExploratory(getExploratoryCreateFormDTO())),
+				eq("project"));
 		verifyNoMoreInteractions(exploratoryService);
 	}
 
 	@Test
 	public void createWithFailedAuth() throws AuthenticationException {
 		authFailSetup();
-		when(exploratoryService.create(any(UserInfo.class), any(Exploratory.class))).thenReturn("someUuid");
+		when(exploratoryService.create(any(UserInfo.class), any(Exploratory.class), anyString())).thenReturn(
+				"someUuid");
 		final Response response = resources.getJerseyTest()
 				.target("/infrastructure_provision/exploratory_environment")
 				.request()
@@ -97,7 +100,7 @@
 	@Test
 	public void createWithException() {
 		doThrow(new DlabException("Could not create exploratory environment"))
-				.when(exploratoryService).create(any(UserInfo.class), any(Exploratory.class));
+				.when(exploratoryService).create(any(UserInfo.class), any(Exploratory.class), anyString());
 		final Response response = resources.getJerseyTest()
 				.target("/infrastructure_provision/exploratory_environment")
 				.request()
@@ -111,13 +114,13 @@
 		assertTrue(actualJson.contains(expectedJson));
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(exploratoryService).create(getUserInfo(), getExploratory(getExploratoryCreateFormDTO()));
+		verify(exploratoryService).create(getUserInfo(), getExploratory(getExploratoryCreateFormDTO()), "project");
 		verifyNoMoreInteractions(exploratoryService);
 	}
 
 	@Test
 	public void start() {
-		when(exploratoryService.start(any(UserInfo.class), anyString())).thenReturn("someUuid");
+		when(exploratoryService.start(any(UserInfo.class), anyString(), anyString())).thenReturn("someUuid");
 		final Response response = resources.getJerseyTest()
 				.target("/infrastructure_provision/exploratory_environment")
 				.request()
@@ -134,7 +137,7 @@
 	@Test
 	public void startWithFailedAuth() throws AuthenticationException {
 		authFailSetup();
-		when(exploratoryService.start(any(UserInfo.class), anyString())).thenReturn("someUuid");
+		when(exploratoryService.start(any(UserInfo.class), anyString(), anyString())).thenReturn("someUuid");
 		final Response response = resources.getJerseyTest()
 				.target("/infrastructure_provision/exploratory_environment")
 				.request()
@@ -303,6 +306,8 @@
 		ecfDto.setShape("someShape");
 		ecfDto.setVersion("someVersion");
 		ecfDto.setImageName("someImageName");
+		ecfDto.setProject("project");
+		ecfDto.setEndpoint("endpoint");
 		return ecfDto;
 	}
 
@@ -317,6 +322,8 @@
 				.imageName(formDTO.getImageName())
 				.templateName(formDTO.getTemplateName())
 				.version(formDTO.getVersion())
-				.shape(formDTO.getShape()).build();
+				.shape(formDTO.getShape())
+				.endpoint(formDTO.getEndpoint())
+				.project(formDTO.getProject()).build();
 	}
 }
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/InfrastructureInfoResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/InfrastructureInfoResourceTest.java
index 30c69ff..e2ab690 100644
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/InfrastructureInfoResourceTest.java
+++ b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/InfrastructureInfoResourceTest.java
@@ -19,6 +19,7 @@
 
 package com.epam.dlab.backendapi.resources;
 
+import com.epam.dlab.auth.UserInfo;
 import com.epam.dlab.backendapi.resources.dto.HealthStatusPageDTO;
 import com.epam.dlab.backendapi.resources.dto.InfrastructureInfo;
 import com.epam.dlab.backendapi.service.InfrastructureInfoService;
@@ -85,7 +86,7 @@
 	@Test
 	public void healthStatus() {
 		HealthStatusPageDTO hspDto = getHealthStatusPageDTO();
-		when(infrastructureInfoService.getHeathStatus(anyString(), anyBoolean(), anyBoolean())).thenReturn(hspDto);
+		when(infrastructureInfoService.getHeathStatus(any(UserInfo.class), anyBoolean(), anyBoolean())).thenReturn(hspDto);
 		final Response response = resources.getJerseyTest()
 				.target("/infrastructure/status")
 				.queryParam("full", "1")
@@ -97,7 +98,7 @@
 		assertEquals(hspDto.getStatus(), response.readEntity(HealthStatusPageDTO.class).getStatus());
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(infrastructureInfoService).getHeathStatus(eq(USER.toLowerCase()), eq(true), anyBoolean());
+		verify(infrastructureInfoService).getHeathStatus(refEq(getUserInfo()), eq(true), anyBoolean());
 		verifyNoMoreInteractions(infrastructureInfoService);
 	}
 
@@ -105,7 +106,7 @@
 	public void healthStatusWithFailedAuth() throws AuthenticationException {
 		authFailSetup();
 		HealthStatusPageDTO hspDto = getHealthStatusPageDTO();
-		when(infrastructureInfoService.getHeathStatus(anyString(), anyBoolean(), anyBoolean())).thenReturn(hspDto);
+		when(infrastructureInfoService.getHeathStatus(any(UserInfo.class), anyBoolean(), anyBoolean())).thenReturn(hspDto);
 		final Response response = resources.getJerseyTest()
 				.target("/infrastructure/status")
 				.queryParam("full", "1")
@@ -117,14 +118,14 @@
 		assertEquals(hspDto.getStatus(), response.readEntity(HealthStatusPageDTO.class).getStatus());
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(infrastructureInfoService).getHeathStatus(eq(USER.toLowerCase()), eq(true), anyBoolean());
+		verify(infrastructureInfoService).getHeathStatus(refEq(getUserInfo()), eq(true), anyBoolean());
 		verifyNoMoreInteractions(infrastructureInfoService);
 	}
 
 	@Test
 	public void healthStatusWithDefaultQueryParam() {
 		HealthStatusPageDTO hspDto = getHealthStatusPageDTO();
-		when(infrastructureInfoService.getHeathStatus(anyString(), anyBoolean(), anyBoolean())).thenReturn(hspDto);
+		when(infrastructureInfoService.getHeathStatus(any(UserInfo.class), anyBoolean(), anyBoolean())).thenReturn(hspDto);
 		final Response response = resources.getJerseyTest()
 				.target("/infrastructure/status")
 				.request()
@@ -135,14 +136,14 @@
 		assertEquals(hspDto.getStatus(), response.readEntity(HealthStatusPageDTO.class).getStatus());
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(infrastructureInfoService).getHeathStatus(eq(USER.toLowerCase()), eq(false), anyBoolean());
+		verify(infrastructureInfoService).getHeathStatus(refEq(getUserInfo()), eq(false), anyBoolean());
 		verifyNoMoreInteractions(infrastructureInfoService);
 	}
 
 	@Test
 	public void healthStatusWithException() {
 		doThrow(new DlabException("Could not return status of resources for user"))
-				.when(infrastructureInfoService).getHeathStatus(anyString(), anyBoolean(), anyBoolean());
+				.when(infrastructureInfoService).getHeathStatus(any(UserInfo.class), anyBoolean(), anyBoolean());
 		final Response response = resources.getJerseyTest()
 				.target("/infrastructure/status")
 				.request()
@@ -152,7 +153,7 @@
 		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(infrastructureInfoService).getHeathStatus(eq(USER.toLowerCase()), eq(false), anyBoolean());
+		verify(infrastructureInfoService).getHeathStatus(refEq(getUserInfo()), eq(false), anyBoolean());
 		verifyNoMoreInteractions(infrastructureInfoService);
 	}
 
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/InfrastructureTemplateResourceTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/InfrastructureTemplateResourceTest.java
index a054ff7..f4f57db 100644
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/InfrastructureTemplateResourceTest.java
+++ b/services/self-service/src/test/java/com/epam/dlab/backendapi/resources/InfrastructureTemplateResourceTest.java
@@ -60,10 +60,10 @@
 	public void getComputationalTemplates() {
 		FullComputationalTemplate fullComputationalTemplate =
 				new FullComputationalTemplate(new ComputationalMetadataDTO());
-		when(infrastructureTemplateService.getComputationalTemplates(any(UserInfo.class)))
+		when(infrastructureTemplateService.getComputationalTemplates(any(UserInfo.class), anyString()))
 				.thenReturn(Collections.singletonList(fullComputationalTemplate));
 		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_templates/computational_templates")
+				.target("/infrastructure_templates/test/computational_templates")
 				.request()
 				.header("Authorization", "Bearer " + TOKEN)
 				.get();
@@ -71,7 +71,7 @@
 		assertEquals(HttpStatus.SC_OK, response.getStatus());
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(infrastructureTemplateService).getComputationalTemplates(getUserInfo());
+		verify(infrastructureTemplateService).getComputationalTemplates(getUserInfo(), "test");
 		verifyNoMoreInteractions(infrastructureTemplateService);
 	}
 
@@ -80,10 +80,10 @@
 		authFailSetup();
 		FullComputationalTemplate fullComputationalTemplate =
 				new FullComputationalTemplate(new ComputationalMetadataDTO());
-		when(infrastructureTemplateService.getComputationalTemplates(any(UserInfo.class)))
+		when(infrastructureTemplateService.getComputationalTemplates(any(UserInfo.class), anyString()))
 				.thenReturn(Collections.singletonList(fullComputationalTemplate));
 		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_templates/computational_templates")
+				.target("/infrastructure_templates/test/computational_templates")
 				.request()
 				.header("Authorization", "Bearer " + TOKEN)
 				.get();
@@ -91,16 +91,16 @@
 		assertEquals(HttpStatus.SC_OK, response.getStatus());
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(infrastructureTemplateService).getComputationalTemplates(getUserInfo());
+		verify(infrastructureTemplateService).getComputationalTemplates(getUserInfo(), "test");
 		verifyNoMoreInteractions(infrastructureTemplateService);
 	}
 
 	@Test
 	public void getComputationalTemplatesWithException() {
 		doThrow(new DlabException("Could not load list of computational templates for user"))
-				.when(infrastructureTemplateService).getComputationalTemplates(any(UserInfo.class));
+				.when(infrastructureTemplateService).getComputationalTemplates(any(UserInfo.class), anyString());
 		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_templates/computational_templates")
+				.target("/infrastructure_templates/test/computational_templates")
 				.request()
 				.header("Authorization", "Bearer " + TOKEN)
 				.get();
@@ -108,7 +108,7 @@
 		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(infrastructureTemplateService).getComputationalTemplates(getUserInfo());
+		verify(infrastructureTemplateService).getComputationalTemplates(getUserInfo(), "test");
 		verifyNoMoreInteractions(infrastructureTemplateService);
 	}
 
@@ -116,10 +116,10 @@
 	public void getExploratoryTemplates() {
 		ExploratoryMetadataDTO exploratoryMetadataDTO =
 				new ExploratoryMetadataDTO("someImageName");
-		when(infrastructureTemplateService.getExploratoryTemplates(any(UserInfo.class)))
+		when(infrastructureTemplateService.getExploratoryTemplates(any(UserInfo.class), anyString()))
 				.thenReturn(Collections.singletonList(exploratoryMetadataDTO));
 		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_templates/exploratory_templates")
+				.target("/infrastructure_templates/test/exploratory_templates")
 				.request()
 				.header("Authorization", "Bearer " + TOKEN)
 				.get();
@@ -130,7 +130,7 @@
 				}));
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(infrastructureTemplateService).getExploratoryTemplates(getUserInfo());
+		verify(infrastructureTemplateService).getExploratoryTemplates(getUserInfo(), "test");
 		verifyNoMoreInteractions(infrastructureTemplateService);
 	}
 
@@ -139,10 +139,10 @@
 		authFailSetup();
 		ExploratoryMetadataDTO exploratoryMetadataDTO =
 				new ExploratoryMetadataDTO("someImageName");
-		when(infrastructureTemplateService.getExploratoryTemplates(any(UserInfo.class)))
+		when(infrastructureTemplateService.getExploratoryTemplates(any(UserInfo.class), anyString()))
 				.thenReturn(Collections.singletonList(exploratoryMetadataDTO));
 		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_templates/exploratory_templates")
+				.target("/infrastructure_templates/test/exploratory_templates")
 				.request()
 				.header("Authorization", "Bearer " + TOKEN)
 				.get();
@@ -153,7 +153,7 @@
 				}));
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(infrastructureTemplateService).getExploratoryTemplates(getUserInfo());
+		verify(infrastructureTemplateService).getExploratoryTemplates(getUserInfo(), "test");
 		verifyNoMoreInteractions(infrastructureTemplateService);
 	}
 
@@ -161,9 +161,9 @@
 	@Test
 	public void getExploratoryTemplatesWithException() {
 		doThrow(new DlabException("Could not load list of exploratory templates for user"))
-				.when(infrastructureTemplateService).getExploratoryTemplates(any(UserInfo.class));
+				.when(infrastructureTemplateService).getExploratoryTemplates(any(UserInfo.class), anyString());
 		final Response response = resources.getJerseyTest()
-				.target("/infrastructure_templates/exploratory_templates")
+				.target("/infrastructure_templates/test/exploratory_templates")
 				.request()
 				.header("Authorization", "Bearer " + TOKEN)
 				.get();
@@ -171,7 +171,7 @@
 		assertEquals(HttpStatus.SC_INTERNAL_SERVER_ERROR, response.getStatus());
 		assertEquals(MediaType.APPLICATION_JSON, response.getHeaderString(HttpHeaders.CONTENT_TYPE));
 
-		verify(infrastructureTemplateService).getExploratoryTemplates(getUserInfo());
+		verify(infrastructureTemplateService).getExploratoryTemplates(getUserInfo(), "test");
 		verifyNoMoreInteractions(infrastructureTemplateService);
 	}
 }
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/roles/UserRolesTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/roles/UserRolesTest.java
index d974c81..0fa4c94 100644
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/roles/UserRolesTest.java
+++ b/services/self-service/src/test/java/com/epam/dlab/backendapi/roles/UserRolesTest.java
@@ -75,14 +75,14 @@
 		when(cursor.next()).thenReturn(doc1).thenReturn(doc2);
 		UserRoles.initialize(dao, true);
 
-		assertTrue(UserRoles.checkAccess(userInfoDev, RoleType.EXPLORATORY_SHAPES, "shape_1"));
-		assertTrue(UserRoles.checkAccess(userInfoDev, RoleType.EXPLORATORY_SHAPES, "shape_2"));
-		assertTrue(UserRoles.checkAccess(userInfoDev, RoleType.EXPLORATORY_SHAPES, "shape_3"));
-		assertTrue(UserRoles.checkAccess(userInfoDev, RoleType.EXPLORATORY_SHAPES, "someShape"));
+		assertTrue(UserRoles.checkAccess(userInfoDev, RoleType.EXPLORATORY_SHAPES, "shape_1", userInfoDev.getRoles()));
+		assertTrue(UserRoles.checkAccess(userInfoDev, RoleType.EXPLORATORY_SHAPES, "shape_2", userInfoDev.getRoles()));
+		assertTrue(UserRoles.checkAccess(userInfoDev, RoleType.EXPLORATORY_SHAPES, "shape_3", userInfoDev.getRoles()));
+		assertTrue(UserRoles.checkAccess(userInfoDev, RoleType.EXPLORATORY_SHAPES, "someShape", userInfoDev.getRoles()));
 
-		assertFalse(UserRoles.checkAccess(userInfoTest, RoleType.EXPLORATORY_SHAPES, "shape_1"));
-		assertFalse(UserRoles.checkAccess(userInfoTest, RoleType.EXPLORATORY_SHAPES, "shape_2"));
-		assertFalse(UserRoles.checkAccess(userInfoTest, RoleType.EXPLORATORY_SHAPES, "shape_3"));
-		assertTrue(UserRoles.checkAccess(userInfoTest, RoleType.EXPLORATORY_SHAPES, "someShape"));
+		assertFalse(UserRoles.checkAccess(userInfoTest, RoleType.EXPLORATORY_SHAPES, "shape_1", userInfoTest.getRoles()));
+		assertFalse(UserRoles.checkAccess(userInfoTest, RoleType.EXPLORATORY_SHAPES, "shape_2", userInfoTest.getRoles()));
+		assertFalse(UserRoles.checkAccess(userInfoTest, RoleType.EXPLORATORY_SHAPES, "shape_3", userInfoTest.getRoles()));
+		assertTrue(UserRoles.checkAccess(userInfoTest, RoleType.EXPLORATORY_SHAPES, "someShape", userInfoTest.getRoles()));
 	}
 }
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImplTest.java
index 6111852..78e8459 100644
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImplTest.java
+++ b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ComputationalServiceImplTest.java
@@ -26,6 +26,7 @@
 import com.epam.dlab.backendapi.domain.RequestId;
 import com.epam.dlab.backendapi.resources.dto.ComputationalCreateFormDTO;
 import com.epam.dlab.backendapi.resources.dto.SparkStandaloneClusterCreateForm;
+import com.epam.dlab.backendapi.service.TagService;
 import com.epam.dlab.backendapi.util.RequestBuilder;
 import com.epam.dlab.dto.SchedulerJobDTO;
 import com.epam.dlab.dto.UserInstanceDTO;
@@ -96,6 +97,8 @@
 	private RequestBuilder requestBuilder;
 	@Mock
 	private RequestId requestId;
+	@Mock
+	private TagService tagService;
 
 	@InjectMocks
 	private ComputationalServiceImpl computationalService;
@@ -130,7 +133,7 @@
 
 		SparkStandaloneClusterCreateForm sparkClusterCreateForm = (SparkStandaloneClusterCreateForm) formList.get(0);
 		boolean creationResult =
-				computationalService.createSparkCluster(userInfo, sparkClusterCreateForm);
+				computationalService.createSparkCluster(userInfo, sparkClusterCreateForm, "");
 		assertTrue(creationResult);
 
 		verify(computationalDAO)
@@ -151,9 +154,12 @@
 	public void createSparkClusterWhenResourceAlreadyExists() {
 		when(computationalDAO.addComputational(anyString(), anyString(),
 				any(SparkStandaloneClusterResource.class))).thenReturn(false);
+		when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString())).thenReturn(userInstance);
+
 
 		boolean creationResult =
-				computationalService.createSparkCluster(userInfo, (SparkStandaloneClusterCreateForm) formList.get(0));
+				computationalService.createSparkCluster(userInfo, (SparkStandaloneClusterCreateForm) formList.get(0),
+						"");
 		assertFalse(creationResult);
 
 		verify(computationalDAO).addComputational(eq(USER), eq(EXPLORATORY_NAME), refEq(sparkClusterResource));
@@ -172,13 +178,14 @@
 
 		SparkStandaloneClusterCreateForm sparkClusterCreateForm = (SparkStandaloneClusterCreateForm) formList.get(0);
 		try {
-			computationalService.createSparkCluster(userInfo, sparkClusterCreateForm);
+			computationalService.createSparkCluster(userInfo, sparkClusterCreateForm, "");
 		} catch (ResourceNotFoundException e) {
 			assertEquals("Exploratory for user with name not found", e.getMessage());
 		}
 
-		verify(computationalDAO).addComputational(USER, EXPLORATORY_NAME, sparkClusterResource);
-		verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed, "self"));
+		verify(computationalDAO, never()).addComputational(USER, EXPLORATORY_NAME, sparkClusterResource);
+		verify(computationalDAO, never()).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed,
+				"self"));
 		verify(exploratoryDAO).fetchExploratoryFields(USER, EXPLORATORY_NAME);
 		verifyNoMoreInteractions(configuration, computationalDAO, exploratoryDAO);
 	}
@@ -198,7 +205,7 @@
 
 		SparkStandaloneClusterCreateForm sparkClusterCreateForm = (SparkStandaloneClusterCreateForm) formList.get(0);
 		try {
-			computationalService.createSparkCluster(userInfo, sparkClusterCreateForm);
+			computationalService.createSparkCluster(userInfo, sparkClusterCreateForm, "");
 		} catch (DlabException e) {
 			assertEquals("Cannot create instance of resource class ", e.getMessage());
 		}
@@ -214,7 +221,7 @@
 		when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
 				.thenReturn(mock(UpdateResult.class));
 		String explId = "explId";
-		when(exploratoryDAO.fetchExploratoryId(anyString(), anyString())).thenReturn(explId);
+		when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString())).thenReturn(userInstance);
 
 		String compId = "compId";
 		UserComputationalResource ucResource = new UserComputationalResource();
@@ -227,7 +234,7 @@
 		ctDto.setComputationalName(COMP_NAME);
 		ctDto.setExploratoryName(EXPLORATORY_NAME);
 		when(requestBuilder.newComputationalTerminate(any(UserInfo.class), anyString(), anyString(), anyString(),
-				anyString(), any(DataEngineType.class))).thenReturn(ctDto);
+				anyString(), any(DataEngineType.class), anyString())).thenReturn(ctDto);
 
 		when(provisioningService.post(anyString(), anyString(), any(ComputationalTerminateDTO.class), any()))
 				.thenReturn(UUID);
@@ -238,15 +245,14 @@
 		verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusTerminating, "self"));
 		verify(computationalDAO).fetchComputationalFields(USER, EXPLORATORY_NAME, COMP_NAME);
 
-		verify(exploratoryDAO).fetchExploratoryId(USER, EXPLORATORY_NAME);
-
 		verify(requestBuilder).newComputationalTerminate(userInfo, EXPLORATORY_NAME, explId, COMP_NAME, compId,
-				DataEngineType.CLOUD_SERVICE);
+				DataEngineType.CLOUD_SERVICE, null);
 
 		verify(provisioningService).post(ComputationalAPI.COMPUTATIONAL_TERMINATE_CLOUD_SPECIFIC, TOKEN, ctDto,
 				String.class);
 
 		verify(requestId).put(USER, UUID);
+		verify(exploratoryDAO).fetchExploratoryFields(USER, EXPLORATORY_NAME);
 		verifyNoMoreInteractions(computationalDAO, exploratoryDAO, requestBuilder, provisioningService, requestId);
 	}
 
@@ -291,7 +297,7 @@
 		verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusTerminating, "self"));
 		verify(computationalDAO).fetchComputationalFields(USER, EXPLORATORY_NAME, COMP_NAME);
 		verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed, "self"));
-		verify(exploratoryDAO).fetchExploratoryId(USER, EXPLORATORY_NAME);
+		verify(exploratoryDAO).fetchExploratoryFields(USER, EXPLORATORY_NAME);
 		verifyNoMoreInteractions(computationalDAO, exploratoryDAO);
 	}
 
@@ -300,7 +306,7 @@
 		when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
 				.thenReturn(mock(UpdateResult.class));
 		String explId = "explId";
-		when(exploratoryDAO.fetchExploratoryId(anyString(), anyString())).thenReturn(explId);
+		when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString())).thenReturn(userInstance);
 
 		String compId = "compId";
 		UserComputationalResource ucResource = new UserComputationalResource();
@@ -311,7 +317,7 @@
 
 		doThrow(new DlabException("Cannot create instance of resource class "))
 				.when(requestBuilder).newComputationalTerminate(any(UserInfo.class), anyString(), anyString(),
-				anyString(), anyString(), any(DataEngineType.class));
+				anyString(), anyString(), any(DataEngineType.class), anyString());
 
 		when(computationalDAO.updateComputationalStatus(any(ComputationalStatusDTO.class)))
 				.thenReturn(mock(UpdateResult.class));
@@ -325,10 +331,10 @@
 		verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusTerminating, "self"));
 		verify(computationalDAO).fetchComputationalFields(USER, EXPLORATORY_NAME, COMP_NAME);
 
-		verify(exploratoryDAO).fetchExploratoryId(USER, EXPLORATORY_NAME);
+		verify(exploratoryDAO).fetchExploratoryFields(USER, EXPLORATORY_NAME);
 
 		verify(requestBuilder).newComputationalTerminate(userInfo, EXPLORATORY_NAME, explId, COMP_NAME, compId,
-				DataEngineType.CLOUD_SERVICE);
+				DataEngineType.CLOUD_SERVICE, null);
 		verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed, "self"));
 		verifyNoMoreInteractions(computationalDAO, exploratoryDAO, requestBuilder);
 	}
@@ -347,7 +353,7 @@
 		when(requestId.put(anyString(), anyString())).thenReturn(UUID);
 
 		boolean creationResult =
-				computationalService.createDataEngineService(userInfo, formList.get(1), ucResource);
+				computationalService.createDataEngineService(userInfo, formList.get(1), ucResource, "");
 		assertTrue(creationResult);
 
 		verify(computationalDAO).addComputational(eq(USER), eq(EXPLORATORY_NAME), refEq(ucResource));
@@ -366,10 +372,12 @@
 
 	@Test
 	public void createDataEngineServiceWhenComputationalResourceNotAdded() {
+		when(exploratoryDAO.fetchExploratoryFields(anyString(), anyString())).thenReturn(userInstance);
 		when(computationalDAO.addComputational(anyString(), anyString(), any(UserComputationalResource.class)))
 				.thenReturn(false);
 
-		boolean creationResult = computationalService.createDataEngineService(userInfo, formList.get(1), ucResource);
+		boolean creationResult = computationalService.createDataEngineService(userInfo, formList.get(1), ucResource,
+				"");
 		assertFalse(creationResult);
 
 		verify(computationalDAO).addComputational(eq(USER), eq(EXPLORATORY_NAME), refEq(ucResource));
@@ -387,18 +395,18 @@
 				.thenReturn(mock(UpdateResult.class));
 
 		try {
-			computationalService.createDataEngineService(userInfo, formList.get(1), ucResource);
+			computationalService.createDataEngineService(userInfo, formList.get(1), ucResource, "");
 		} catch (DlabException e) {
-			assertEquals("Could not send request for creation the computational resource compName: " +
-					"Exploratory for user with name not found", e.getMessage());
+			assertEquals("Exploratory for user with name not found", e.getMessage());
 		}
 
-		verify(computationalDAO)
+		verify(computationalDAO, never())
 				.addComputational(eq(USER), eq(EXPLORATORY_NAME), refEq(ucResource));
 
 		verify(exploratoryDAO).fetchExploratoryFields(USER, EXPLORATORY_NAME);
 
-		verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed, "self"));
+		verify(computationalDAO, never()).updateComputationalStatus(refEq(computationalStatusDTOWithStatusFailed,
+				"self"));
 		verifyNoMoreInteractions(computationalDAO, exploratoryDAO);
 	}
 
@@ -417,7 +425,7 @@
 
 		ComputationalCreateFormDTO computationalCreateFormDTO = formList.get(1);
 		try {
-			computationalService.createDataEngineService(userInfo, computationalCreateFormDTO, ucResource);
+			computationalService.createDataEngineService(userInfo, computationalCreateFormDTO, ucResource, "");
 		} catch (DlabException e) {
 			assertEquals("Could not send request for creation the computational resource compName: " +
 					"Cannot create instance of resource class ", e.getMessage());
@@ -485,7 +493,7 @@
 				.thenReturn("someUuid");
 		when(requestId.put(anyString(), anyString())).thenReturn("someUuid");
 
-		computationalService.startSparkCluster(userInfo, EXPLORATORY_NAME, COMP_NAME);
+		computationalService.startSparkCluster(userInfo, EXPLORATORY_NAME, COMP_NAME, "");
 
 		verify(computationalDAO).updateComputationalStatus(refEq(computationalStatusDTOWithStatusStarting, "self"));
 		verify(exploratoryDAO).fetchExploratoryFields(USER, EXPLORATORY_NAME, true);
@@ -507,7 +515,7 @@
 		expectedException.expect(IllegalStateException.class);
 		expectedException.expectMessage("There is no stopped dataengine compName for exploratory expName");
 
-		computationalService.startSparkCluster(userInfo, EXPLORATORY_NAME, COMP_NAME);
+		computationalService.startSparkCluster(userInfo, EXPLORATORY_NAME, COMP_NAME, "");
 	}
 
 	@Test
@@ -658,7 +666,9 @@
 	}
 
 	private UserInstanceDTO getUserInstanceDto() {
-		return new UserInstanceDTO().withUser(USER).withExploratoryName(EXPLORATORY_NAME);
+		return new UserInstanceDTO().withUser(USER).withExploratoryName(EXPLORATORY_NAME)
+				.withExploratoryId("explId")
+				.withTags(Collections.emptyMap());
 	}
 
 	private List<ComputationalCreateFormDTO> getFormList() {
@@ -670,6 +680,7 @@
 		ComputationalCreateFormDTO desClusterForm = new ComputationalCreateFormDTO();
 		desClusterForm.setNotebookName(EXPLORATORY_NAME);
 		desClusterForm.setName(COMP_NAME);
+
 		return Arrays.asList(sparkClusterForm, desClusterForm);
 	}
 
@@ -687,6 +698,7 @@
 				.imageName("dataengine")
 				.status(CREATING.toString())
 				.dataEngineInstanceCount(String.valueOf(2))
+				.tags(Collections.emptyMap())
 				.build();
 	}
 
@@ -698,6 +710,7 @@
 		ucResource.setStatus(status.toString());
 		ucResource.setLastActivity(LAST_ACTIVITY);
 		ucResource.setComputationalId(COMP_ID);
+		ucResource.setTags(Collections.emptyMap());
 		final SchedulerJobDTO schedulerData = new SchedulerJobDTO();
 		schedulerData.setCheckInactivityRequired(true);
 		schedulerData.setMaxInactivity(MAX_INACTIVITY);
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImplTest.java
index 1dce004..5d63724 100644
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImplTest.java
+++ b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/EnvironmentServiceImplTest.java
@@ -25,11 +25,13 @@
 import com.epam.dlab.backendapi.dao.ExploratoryDAO;
 import com.epam.dlab.backendapi.dao.KeyDAO;
 import com.epam.dlab.backendapi.dao.UserSettingsDAO;
+import com.epam.dlab.backendapi.domain.ProjectDTO;
 import com.epam.dlab.backendapi.resources.dto.UserDTO;
 import com.epam.dlab.backendapi.resources.dto.UserResourceInfo;
 import com.epam.dlab.backendapi.service.ComputationalService;
 import com.epam.dlab.backendapi.service.EdgeService;
 import com.epam.dlab.backendapi.service.ExploratoryService;
+import com.epam.dlab.backendapi.service.ProjectService;
 import com.epam.dlab.dto.UserInstanceDTO;
 import com.epam.dlab.dto.UserInstanceStatus;
 import com.epam.dlab.dto.base.edge.EdgeInfo;
@@ -77,6 +79,8 @@
 	private KeyDAO keyDAO;
 	@Mock
 	private UserSettingsDAO userSettingsDAO;
+	@Mock
+	private ProjectService projectService;
 
 	@InjectMocks
 	private EnvironmentServiceImpl environmentService;
@@ -137,8 +141,11 @@
 	@Test
 	public void getAllEnv() {
 		List<UserInstanceDTO> instances = getUserInstances();
+		final ProjectDTO project = new ProjectDTO("prj", Collections.emptySet(), Collections.emptySet(),
+				"key", "tag", null);
+		project.setEdgeInfo(new EdgeInfo());
 		when(exploratoryDAO.getInstances()).thenReturn(instances);
-		doReturn(Collections.singleton(USER)).when(envDAO).fetchAllUsers();
+		doReturn(Collections.singletonList(project)).when(projectService).getProjectsWithStatus(ProjectDTO.Status.ACTIVE);
 
 		EdgeInfo edgeInfo = new EdgeInfo();
 		edgeInfo.setEdgeStatus("running");
@@ -157,15 +164,11 @@
 				.withResourceStatus(instances.get(1).getStatus()).withUser(instances.get(1)
 						.getUser());
 
-		List<UserResourceInfo> resources = Arrays.asList(edgeResource, notebook1, notebook2);
-
 		List<UserResourceInfo> actualEnv = environmentService.getAllEnv();
 		assertEquals(3, actualEnv.size());
-		resources.forEach(resource -> assertTrue(actualEnv.contains(resource)));
 
 		verify(exploratoryDAO).getInstances();
-		verify(envDAO).fetchAllUsers();
-		verify(keyDAO).getEdgeInfo(USER);
+		verify(projectService).getProjectsWithStatus(ProjectDTO.Status.ACTIVE);
 		verifyNoMoreInteractions(exploratoryDAO, envDAO, keyDAO);
 	}
 
@@ -541,7 +544,7 @@
 
 	private List<UserInstanceDTO> getUserInstances() {
 		return Arrays.asList(
-				new UserInstanceDTO().withExploratoryName(EXPLORATORY_NAME_1).withUser(USER),
-				new UserInstanceDTO().withExploratoryName(EXPLORATORY_NAME_2).withUser(USER));
+				new UserInstanceDTO().withExploratoryName(EXPLORATORY_NAME_1).withUser(USER).withProject("prj"),
+				new UserInstanceDTO().withExploratoryName(EXPLORATORY_NAME_2).withUser(USER).withProject("prj"));
 	}
 }
\ No newline at end of file
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImplTest.java
index 2c28539..6a4e771 100644
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImplTest.java
+++ b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/ExploratoryServiceImplTest.java
@@ -24,6 +24,7 @@
 import com.epam.dlab.backendapi.dao.ExploratoryDAO;
 import com.epam.dlab.backendapi.dao.GitCredsDAO;
 import com.epam.dlab.backendapi.domain.RequestId;
+import com.epam.dlab.backendapi.service.TagService;
 import com.epam.dlab.backendapi.util.RequestBuilder;
 import com.epam.dlab.dto.StatusEnvBaseDTO;
 import com.epam.dlab.dto.UserInstanceDTO;
@@ -78,6 +79,8 @@
 	private RequestBuilder requestBuilder;
 	@Mock
 	private RequestId requestId;
+	@Mock
+	private TagService tagService;
 
 	@InjectMocks
 	private ExploratoryServiceImpl exploratoryService;
@@ -109,7 +112,7 @@
 				.thenReturn(UUID);
 		when(requestId.put(anyString(), anyString())).thenReturn(UUID);
 
-		String uuid = exploratoryService.start(userInfo, EXPLORATORY_NAME);
+		String uuid = exploratoryService.start(userInfo, EXPLORATORY_NAME, "project");
 		assertNotNull(uuid);
 		assertEquals(UUID, uuid);
 
@@ -128,7 +131,7 @@
 		doThrow(new ResourceNotFoundException("Exploratory for user with name not found"))
 				.when(exploratoryDAO).fetchExploratoryFields(anyString(), anyString());
 		try {
-			exploratoryService.start(userInfo, EXPLORATORY_NAME);
+			exploratoryService.start(userInfo, EXPLORATORY_NAME, "project");
 		} catch (DlabException e) {
 			assertEquals("Could not exploratory/start exploratory environment expName: Exploratory for user with " +
 					"name not found", e.getMessage());
@@ -254,13 +257,13 @@
 		ExploratoryCreateDTO ecDto = new ExploratoryCreateDTO();
 		Exploratory exploratory = Exploratory.builder().name(EXPLORATORY_NAME).build();
 		when(requestBuilder.newExploratoryCreate(any(Exploratory.class), any(UserInfo.class),
-				any(ExploratoryGitCredsDTO.class))).thenReturn(ecDto);
+				any(ExploratoryGitCredsDTO.class), anyMapOf(String.class, String.class))).thenReturn(ecDto);
 		String exploratoryCreate = "exploratory/create";
 		when(provisioningService.post(anyString(), anyString(), any(ExploratoryCreateDTO.class), any()))
 				.thenReturn(UUID);
 		when(requestId.put(anyString(), anyString())).thenReturn(UUID);
 
-		String uuid = exploratoryService.create(userInfo, exploratory);
+		String uuid = exploratoryService.create(userInfo, exploratory, "project");
 		assertNotNull(uuid);
 		assertEquals(UUID, uuid);
 
@@ -268,7 +271,7 @@
 		userInstance.withResources(Collections.emptyList());
 		verify(exploratoryDAO).insertExploratory(userInstance);
 		verify(gitCredsDAO).findGitCreds(USER);
-		verify(requestBuilder).newExploratoryCreate(exploratory, userInfo, egcDto);
+		verify(requestBuilder).newExploratoryCreate(exploratory, userInfo, egcDto, Collections.emptyMap());
 		verify(provisioningService).post(exploratoryCreate, TOKEN, ecDto, String.class);
 		verify(requestId).put(USER, UUID);
 		verifyNoMoreInteractions(exploratoryDAO, gitCredsDAO, requestBuilder, provisioningService, requestId);
@@ -283,7 +286,7 @@
 				"Exploratory for user with name not found");
 
 		Exploratory exploratory = Exploratory.builder().name(EXPLORATORY_NAME).build();
-		exploratoryService.create(userInfo, exploratory);
+		exploratoryService.create(userInfo, exploratory, "project");
 	}
 
 	@Test
@@ -291,7 +294,7 @@
 		doThrow(new RuntimeException()).when(exploratoryDAO).insertExploratory(any(UserInstanceDTO.class));
 		Exploratory exploratory = Exploratory.builder().name(EXPLORATORY_NAME).build();
 		try {
-			exploratoryService.create(userInfo, exploratory);
+			exploratoryService.create(userInfo, exploratory, "project");
 		} catch (DlabException e) {
 			assertEquals("Could not create exploratory environment expName for user test: null",
 					e.getMessage());
@@ -312,11 +315,12 @@
 		Exploratory exploratory = Exploratory.builder().name(EXPLORATORY_NAME).build();
 
 		doThrow(new DlabException("Cannot create instance of resource class ")).when(requestBuilder)
-				.newExploratoryCreate(any(Exploratory.class), any(UserInfo.class), any(ExploratoryGitCredsDTO.class));
+				.newExploratoryCreate(any(Exploratory.class), any(UserInfo.class), any(ExploratoryGitCredsDTO.class),
+						anyMapOf(String.class, String.class));
 
 		when(exploratoryDAO.updateExploratoryStatus(any(StatusEnvBaseDTO.class))).thenReturn(mock(UpdateResult.class));
 		try {
-			exploratoryService.create(userInfo, exploratory);
+			exploratoryService.create(userInfo, exploratory, "project");
 		} catch (DlabException e) {
 			assertEquals("Could not create exploratory environment expName for user test: Cannot create instance " +
 					"of resource class ", e.getMessage());
@@ -328,7 +332,7 @@
 		userInstance.withResources(Collections.emptyList());
 		verify(exploratoryDAO).insertExploratory(userInstance);
 		verify(gitCredsDAO).findGitCreds(USER);
-		verify(requestBuilder).newExploratoryCreate(exploratory, userInfo, egcDto);
+		verify(requestBuilder).newExploratoryCreate(exploratory, userInfo, egcDto, Collections.emptyMap());
 		verify(exploratoryDAO).updateExploratoryStatus(refEq(statusEnvBaseDTO, "self"));
 		verifyNoMoreInteractions(exploratoryDAO, gitCredsDAO, requestBuilder);
 	}
@@ -526,7 +530,9 @@
 		compResource.setStatus("stopped");
 		compResource.setComputationalId("compId");
 		return new UserInstanceDTO().withUser(USER).withExploratoryName(EXPLORATORY_NAME).withStatus("running")
-				.withResources(singletonList(compResource));
+				.withResources(singletonList(compResource))
+				.withTags(Collections.emptyMap())
+				.withProject("project");
 	}
 
 	private StatusEnvBaseDTO getStatusEnvBaseDTOWithStatus(String status) {
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceBaseTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceBaseTest.java
index aad8094..2c7d127 100644
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceBaseTest.java
+++ b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/InfrastructureInfoServiceBaseTest.java
@@ -19,6 +19,7 @@
 
 package com.epam.dlab.backendapi.service.impl;
 
+import com.epam.dlab.auth.UserInfo;
 import com.epam.dlab.backendapi.SelfServiceApplicationConfiguration;
 import com.epam.dlab.backendapi.dao.BillingDAO;
 import com.epam.dlab.backendapi.dao.EnvDAO;
@@ -27,6 +28,7 @@
 import com.epam.dlab.backendapi.resources.dto.HealthStatusEnum;
 import com.epam.dlab.backendapi.resources.dto.HealthStatusPageDTO;
 import com.epam.dlab.backendapi.resources.dto.InfrastructureInfo;
+import com.epam.dlab.backendapi.service.ProjectService;
 import com.epam.dlab.dto.base.edge.EdgeInfo;
 import com.epam.dlab.exceptions.DlabException;
 import org.bson.Document;
@@ -57,6 +59,8 @@
 	private SelfServiceApplicationConfiguration configuration;
 	@Mock
 	private BillingDAO billingDAO;
+	@Mock
+	private ProjectService projectService;
 
 	@InjectMocks
 	private InfrastructureInfoServiceBase infrastructureInfoServiceBase = spy(InfrastructureInfoServiceBase.class);
@@ -109,11 +113,12 @@
 		when(billingDAO.getBillingQuoteUsed()).thenReturn(10);
 
 		HealthStatusPageDTO actualHealthStatusPageDTO =
-				infrastructureInfoServiceBase.getHeathStatus(USER, false, true);
+				infrastructureInfoServiceBase.getHeathStatus(new UserInfo(USER, "token"), false, true);
 		assertNotNull(actualHealthStatusPageDTO);
 		assertEquals(HealthStatusEnum.OK.toString(), actualHealthStatusPageDTO.getStatus());
 		assertFalse(actualHealthStatusPageDTO.isBillingEnabled());
 		assertTrue(actualHealthStatusPageDTO.isAdmin());
+		assertFalse(actualHealthStatusPageDTO.isProjectAssigned());
 		assertEquals(10, actualHealthStatusPageDTO.getBillingQuoteUsed());
 
 		verify(envDAO).getHealthStatusPageDTO(USER, false);
@@ -126,7 +131,7 @@
 		doThrow(new DlabException("Cannot fetch health status!"))
 				.when(envDAO).getHealthStatusPageDTO(anyString(), anyBoolean());
 		try {
-			infrastructureInfoServiceBase.getHeathStatus(USER, false, false);
+			infrastructureInfoServiceBase.getHeathStatus(new UserInfo(USER, null), false, false);
 		} catch (DlabException e) {
 			assertEquals("Cannot fetch health status!", e.getMessage());
 		}
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceBaseTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceBaseTest.java
index 225a5c8..834f2f1 100644
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceBaseTest.java
+++ b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/InfrastructureTemplateServiceBaseTest.java
@@ -20,7 +20,9 @@
 package com.epam.dlab.backendapi.service.impl;
 
 import com.epam.dlab.auth.UserInfo;
+import com.epam.dlab.backendapi.dao.ProjectDAO;
 import com.epam.dlab.backendapi.dao.SettingsDAO;
+import com.epam.dlab.backendapi.domain.ProjectDTO;
 import com.epam.dlab.dto.base.computational.FullComputationalTemplate;
 import com.epam.dlab.dto.imagemetadata.ComputationalMetadataDTO;
 import com.epam.dlab.dto.imagemetadata.ComputationalResourceShapeDto;
@@ -34,10 +36,7 @@
 import org.mockito.runners.MockitoJUnitRunner;
 
 import java.lang.reflect.Field;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
+import java.util.*;
 import java.util.stream.Collectors;
 
 import static org.junit.Assert.*;
@@ -50,6 +49,8 @@
 	private SettingsDAO settingsDAO;
 	@Mock
 	private RESTService provisioningService;
+	@Mock
+	private ProjectDAO projectDAO;
 
 	@InjectMocks
 	private InfrastructureTemplateServiceBaseChild infrastructureTemplateServiceBaseChild =
@@ -75,12 +76,14 @@
 						"someRam2", 6)));
 		emDto2.setExploratoryEnvironmentShapes(shapes2);
 		List<ExploratoryMetadataDTO> expectedEmdDtoList = Arrays.asList(emDto1, emDto2);
+		when(projectDAO.get(anyString())).thenReturn(Optional.of(new ProjectDTO("project", Collections.emptySet(),
+				Collections.singleton("project"), null, null, null)));
 		when(provisioningService.get(anyString(), anyString(), any())).thenReturn(expectedEmdDtoList.toArray());
 		when(settingsDAO.getConfOsFamily()).thenReturn("someConfOsFamily");
 
 		UserInfo userInfo = new UserInfo("test", "token");
 		List<ExploratoryMetadataDTO> actualEmdDtoList =
-				infrastructureTemplateServiceBaseChild.getExploratoryTemplates(userInfo);
+				infrastructureTemplateServiceBaseChild.getExploratoryTemplates(userInfo, "project");
 		assertNotNull(actualEmdDtoList);
 		assertEquals(expectedEmdDtoList, actualEmdDtoList);
 
@@ -96,7 +99,7 @@
 
 		UserInfo userInfo = new UserInfo("test", "token");
 		try {
-			infrastructureTemplateServiceBaseChild.getExploratoryTemplates(userInfo);
+			infrastructureTemplateServiceBaseChild.getExploratoryTemplates(userInfo, "project");
 		} catch (DlabException e) {
 			assertEquals("Could not load list of exploratory templates for user", e.getMessage());
 		}
@@ -106,11 +109,14 @@
 
 	@Test
 	public void getComputationalTemplates() throws NoSuchFieldException, IllegalAccessException {
+
 		final ComputationalMetadataDTO computationalMetadataDTO = new ComputationalMetadataDTO("dataengine-service");
 		computationalMetadataDTO.setComputationResourceShapes(Collections.emptyMap());
 		List<ComputationalMetadataDTO> expectedCmdDtoList = Collections.singletonList(
 				computationalMetadataDTO
 		);
+		when(projectDAO.get(anyString())).thenReturn(Optional.of(new ProjectDTO("project", Collections.emptySet(),
+				Collections.singleton("project"), null, null, null)));
 		when(provisioningService.get(anyString(), anyString(), any())).thenReturn(expectedCmdDtoList.toArray(new ComputationalMetadataDTO[]{}));
 
 		List<FullComputationalTemplate> expectedFullCmdDtoList = expectedCmdDtoList.stream()
@@ -119,7 +125,7 @@
 
 		UserInfo userInfo = new UserInfo("test", "token");
 		List<FullComputationalTemplate> actualFullCmdDtoList =
-				infrastructureTemplateServiceBaseChild.getComputationalTemplates(userInfo);
+				infrastructureTemplateServiceBaseChild.getComputationalTemplates(userInfo, "project");
 		assertNotNull(actualFullCmdDtoList);
 		assertEquals(expectedFullCmdDtoList.size(), actualFullCmdDtoList.size());
 		for (int i = 0; i < expectedFullCmdDtoList.size(); i++) {
@@ -137,7 +143,7 @@
 
 		UserInfo userInfo = new UserInfo("test", "token");
 		try {
-			infrastructureTemplateServiceBaseChild.getComputationalTemplates(userInfo);
+			infrastructureTemplateServiceBaseChild.getComputationalTemplates(userInfo, "project");
 		} catch (DlabException e) {
 			assertEquals("Could not load list of computational templates for user", e.getMessage());
 		}
@@ -151,10 +157,12 @@
 		computationalMetadataDTO.setComputationResourceShapes(Collections.emptyMap());
 		List<ComputationalMetadataDTO> expectedCmdDtoList = Collections.singletonList(computationalMetadataDTO);
 		when(provisioningService.get(anyString(), anyString(), any())).thenReturn(expectedCmdDtoList.toArray(new ComputationalMetadataDTO[]{}));
+		when(projectDAO.get(anyString())).thenReturn(Optional.of(new ProjectDTO("project", Collections.emptySet(),
+				Collections.singleton("project"), null, null,null)));
 
 		UserInfo userInfo = new UserInfo("test", "token");
 		try {
-			infrastructureTemplateServiceBaseChild.getComputationalTemplates(userInfo);
+			infrastructureTemplateServiceBaseChild.getComputationalTemplates(userInfo, "project");
 		} catch (IllegalArgumentException e) {
 			assertEquals("Unknown data engine null", e.getMessage());
 		}
@@ -165,6 +173,7 @@
 	private boolean areFullComputationalTemplatesEqual(FullComputationalTemplate object1,
 													   FullComputationalTemplate object2) throws NoSuchFieldException,
 			IllegalAccessException {
+		String project = "";//TODO CHANGEIT
 		Field computationalMetadataDTO1 = object1.getClass().getDeclaredField("computationalMetadataDTO");
 		computationalMetadataDTO1.setAccessible(true);
 		Field computationalMetadataDTO2 = object2.getClass().getDeclaredField("computationalMetadataDTO");
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/SchedulerJobServiceImplTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/SchedulerJobServiceImplTest.java
index 4ca2ca0..55bfcbc 100644
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/SchedulerJobServiceImplTest.java
+++ b/services/self-service/src/test/java/com/epam/dlab/backendapi/service/impl/SchedulerJobServiceImplTest.java
@@ -399,7 +399,7 @@
 		verify(schedulerJobDAO)
 				.getComputationalSchedulerDataWithOneOfStatus(RUNNING, DataEngineType.SPARK_STANDALONE, STOPPED);
 		verify(computationalService).startSparkCluster(refEq(getUserInfo()), eq(EXPLORATORY_NAME),
-				eq(COMPUTATIONAL_NAME));
+				eq(COMPUTATIONAL_NAME), eq(""));
 		verifyNoMoreInteractions(systemUserService, schedulerJobDAO, computationalService);
 	}
 
@@ -691,7 +691,7 @@
 
 		verify(systemUserService).create(USER);
 		verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
-		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME));
+		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME),  eq(""));
 		verifyNoMoreInteractions(systemUserService, schedulerJobDAO, exploratoryService);
 		verifyZeroInteractions(computationalService, computationalDAO);
 	}
@@ -715,10 +715,10 @@
 
 		verify(systemUserService, times(2)).create(USER);
 		verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
-		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME));
+		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME), eq(""));
 		verify(computationalDAO).findComputationalResourcesWithStatus(USER, EXPLORATORY_NAME, STOPPED);
 		verify(computationalService).startSparkCluster(refEq(getUserInfo()), eq(EXPLORATORY_NAME),
-				eq(COMPUTATIONAL_NAME));
+				eq(COMPUTATIONAL_NAME),  eq(""));
 		verifyNoMoreInteractions(systemUserService, schedulerJobDAO, exploratoryService, computationalService,
 				computationalDAO);
 	}
@@ -742,7 +742,7 @@
 
 		verify(systemUserService).create(USER);
 		verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
-		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME));
+		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME),  eq(""));
 		verify(computationalDAO).findComputationalResourcesWithStatus(USER, EXPLORATORY_NAME, STOPPED);
 		verifyNoMoreInteractions(systemUserService, schedulerJobDAO, exploratoryService, computationalDAO);
 		verifyZeroInteractions(computationalService);
@@ -767,7 +767,7 @@
 
 		verify(systemUserService).create(USER);
 		verify(schedulerJobDAO).getExploratorySchedulerDataWithStatus(STOPPED);
-		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME));
+		verify(exploratoryService).start(refEq(getUserInfo()), eq(EXPLORATORY_NAME),  eq(""));
 		verify(computationalDAO).findComputationalResourcesWithStatus(USER, EXPLORATORY_NAME, STOPPED);
 		verifyNoMoreInteractions(systemUserService, schedulerJobDAO, exploratoryService, computationalDAO);
 		verifyZeroInteractions(computationalService);
diff --git a/services/self-service/src/test/java/com/epam/dlab/backendapi/util/RequestBuilderTest.java b/services/self-service/src/test/java/com/epam/dlab/backendapi/util/RequestBuilderTest.java
index adb46f0..82fd834 100644
--- a/services/self-service/src/test/java/com/epam/dlab/backendapi/util/RequestBuilderTest.java
+++ b/services/self-service/src/test/java/com/epam/dlab/backendapi/util/RequestBuilderTest.java
@@ -308,7 +308,7 @@
 		when(settingsDAO.getAwsVpcId()).thenReturn("someAwsVpcId");
 		when(settingsDAO.getConfTagResourceId()).thenReturn("someConfTagResourceId");
 
-		requestBuilder.newExploratoryCreate(exploratory, userInfo, egcDto);
+		requestBuilder.newExploratoryCreate(exploratory, userInfo, egcDto, null);
 
 		verify(configuration, times(3)).getCloudProvider();
 		verify(settingsDAO).getServiceBaseName();
@@ -336,7 +336,7 @@
 		when(settingsDAO.getAzureVpcName()).thenReturn("someAzureVpcId");
 		when(settingsDAO.getAzureDataLakeClientId()).thenReturn("someId");
 
-		requestBuilder.newExploratoryCreate(exploratory, userInfo, egcDto);
+		requestBuilder.newExploratoryCreate(exploratory, userInfo, egcDto, null);
 
 		verify(configuration, times(3)).getCloudProvider();
 		verify(settingsDAO, times(2)).isAzureDataLakeEnabled();
@@ -357,7 +357,7 @@
 		when(settingsDAO.getServiceBaseName()).thenReturn("someSBN");
 		when(settingsDAO.getConfOsFamily()).thenReturn("someConfOsFamily");
 
-		requestBuilder.newExploratoryCreate(exploratory, userInfo, egcDto);
+		requestBuilder.newExploratoryCreate(exploratory, userInfo, egcDto, null);
 
 		verify(configuration, times(3)).getCloudProvider();
 		verify(configuration).getMaxUserNameLength();
@@ -972,7 +972,7 @@
 		when(settingsDAO.getConfTagResourceId()).thenReturn("someConfTagResourceId");
 
 		requestBuilder.newComputationalTerminate(userInfo, "explName", "explId", "compName",
-				"compId", DataEngineType.CLOUD_SERVICE);
+				"compId", DataEngineType.CLOUD_SERVICE, "");
 
 		verify(configuration, times(3)).getCloudProvider();
 		verify(settingsDAO).getServiceBaseName();
@@ -999,7 +999,7 @@
 		when(settingsDAO.getAzureVpcName()).thenReturn("someAzureVpcId");
 
 		requestBuilder.newComputationalTerminate(userInfo, "explName", "explId", "compName",
-				"compId", DataEngineType.CLOUD_SERVICE);
+				"compId", DataEngineType.CLOUD_SERVICE, "");
 
 		verify(configuration, times(3)).getCloudProvider();
 		verify(settingsDAO).getServiceBaseName();
@@ -1020,7 +1020,7 @@
 		when(settingsDAO.getConfOsFamily()).thenReturn("someConfOsFamily");
 
 		requestBuilder.newComputationalTerminate(userInfo, "explName", "explId", "compName",
-				"compId", DataEngineType.CLOUD_SERVICE);
+				"compId", DataEngineType.CLOUD_SERVICE, "");
 
 		verify(configuration, times(3)).getCloudProvider();
 		verify(configuration).getMaxUserNameLength();