You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ma...@apache.org on 2018/08/17 19:35:56 UTC

[airavata-django-portal] branch master updated (6d6d0ac -> f49ed31)

This is an automated email from the ASF dual-hosted git repository.

machristie pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git.


    from 6d6d0ac  AIRAVATA-2727 Credential token editor
     new 7545f27  AIRAVATA-2727 AIRAVATA-2638 Global error handling
     new ceb0b5b  AIRAVATA-2727 Handle uncaught TExceptions
     new 5e6f01f  AIRAVATA-2727 AIRAVATA-2638 Vue global error handler
     new fd7c1d5  AIRAVATA-2727 Removing TODOs
     new f49ed31  AIRAVATA-2727 Clean up Notification api

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../ComputePreference.vue                          |  12 -
 .../GroupComputeResourcePreference.vue             |  13 +-
 .../ComputeResourcePreferenceDashboard.vue         |   8 +-
 .../admin/static/django_airavata_admin/src/main.js |   9 +-
 django_airavata/apps/api/exceptions.py             |  33 ++
 django_airavata/apps/api/serializers.py            |  12 +-
 .../django_airavata_api/js/errors/ErrorReporter.js |   9 +
 .../js/errors/UnhandledError.js                    |  15 +
 .../js/errors/UnhandledErrorDispatcher.js          |  18 +
 .../js/errors/UnhandledErrorDisplayList.js         |  21 +
 .../api/static/django_airavata_api/js/index.js     |  12 +-
 .../js/services/ServiceFactory.js                  |  12 +-
 .../django_airavata_api/js/utils/FetchUtils.js     | 133 ++++---
 django_airavata/apps/api/thrift_utils.py           |   8 +-
 django_airavata/apps/api/views.py                  |   4 +-
 django_airavata/settings.py                        |   2 +
 .../common/js/components/NotificationsDisplay.vue  |  62 +++
 .../static/common/js/errors/GlobalErrorHandler.js  |  37 ++
 django_airavata/static/common/js/index.js          |   8 +
 .../static/common/js/notifications/Notification.js |  15 +
 .../common/js/notifications/NotificationList.js    |  22 ++
 django_airavata/static/common/package-lock.json    | 424 +++++----------------
 22 files changed, 457 insertions(+), 432 deletions(-)
 create mode 100644 django_airavata/apps/api/exceptions.py
 create mode 100644 django_airavata/apps/api/static/django_airavata_api/js/errors/ErrorReporter.js
 create mode 100644 django_airavata/apps/api/static/django_airavata_api/js/errors/UnhandledError.js
 create mode 100644 django_airavata/apps/api/static/django_airavata_api/js/errors/UnhandledErrorDispatcher.js
 create mode 100644 django_airavata/apps/api/static/django_airavata_api/js/errors/UnhandledErrorDisplayList.js
 create mode 100644 django_airavata/static/common/js/components/NotificationsDisplay.vue
 create mode 100644 django_airavata/static/common/js/errors/GlobalErrorHandler.js
 create mode 100644 django_airavata/static/common/js/notifications/Notification.js
 create mode 100644 django_airavata/static/common/js/notifications/NotificationList.js


[airavata-django-portal] 05/05: AIRAVATA-2727 Clean up Notification api

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit f49ed31aef10279e8ba3af3cc96d318d1fde2e99
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Fri Aug 17 15:35:44 2018 -0400

    AIRAVATA-2727 Clean up Notification api
---
 .../js/errors/UnhandledError.js                    |  4 ----
 .../common/js/components/NotificationsDisplay.vue  | 25 ++++++----------------
 .../static/common/js/notifications/Notification.js |  5 +++--
 .../common/js/notifications/NotificationList.js    |  9 --------
 4 files changed, 9 insertions(+), 34 deletions(-)

diff --git a/django_airavata/apps/api/static/django_airavata_api/js/errors/UnhandledError.js b/django_airavata/apps/api/static/django_airavata_api/js/errors/UnhandledError.js
index 33a80ae..53524c6 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/errors/UnhandledError.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/errors/UnhandledError.js
@@ -10,10 +10,6 @@ class UnhandledError {
         this.suppressLogging = suppressLogging;
         this.createdDate = new Date();
     }
-
-    get displayMessage() {
-        return this.error && this.error.message ? this.error.message : this.message;
-    }
 }
 
 export default UnhandledError;
diff --git a/django_airavata/static/common/js/components/NotificationsDisplay.vue b/django_airavata/static/common/js/components/NotificationsDisplay.vue
index d725d6c..425d25d 100644
--- a/django_airavata/static/common/js/components/NotificationsDisplay.vue
+++ b/django_airavata/static/common/js/components/NotificationsDisplay.vue
@@ -1,10 +1,10 @@
 <template>
     <div id="notifications-display">
         <transition-group name="fade" tag="div">
-            <b-alert v-for="error in errors"
-                    :variant="variant(error)" :key="error.id"
-                    show dismissible @dismissed="dismissedError(error)">
-                {{ error.message }}
+            <b-alert v-for="unhandledError in unhandledErrors"
+                    variant="danger" :key="unhandledError.id"
+                    show dismissible @dismissed="dismissedUnhandledError(unhandledError)">
+                {{ unhandledError.message }}
             </b-alert>
             <b-alert v-for="notification in notifications"
                     :variant="variant(notification)" :key="notification.id"
@@ -29,25 +29,12 @@ export default {
             unhandledErrors: errors.UnhandledErrorDisplayList.list,
         }
     },
-    computed: {
-        errors: function() {
-
-            return this.unhandledErrors.map(unhandledError => {
-                return new Notification("UNHANDLED-ERROR-" + unhandledError.id, {
-                    type: "ERROR",
-                    message: unhandledError.displayMessage,
-                    details: unhandledError,
-                    createdDate: unhandledError.createdDate,
-                });
-            })
-        }
-    },
     methods: {
         dismissedNotification: function(notification) {
             NotificationList.remove(notification);
         },
-        dismissedError: function(error) {
-            errors.UnhandledErrorDisplayList.remove(error.details);
+        dismissUnhandledError: function(unhandledError) {
+            errors.UnhandledErrorDisplayList.remove(unhandledError);
         },
         variant: function(notification) {
             if (notification.type === "SUCCESS") {
diff --git a/django_airavata/static/common/js/notifications/Notification.js b/django_airavata/static/common/js/notifications/Notification.js
index 1b8864e..2a481e6 100644
--- a/django_airavata/static/common/js/notifications/Notification.js
+++ b/django_airavata/static/common/js/notifications/Notification.js
@@ -1,7 +1,8 @@
 
+let idSequence = 0;
 class Notification {
-    constructor(id, { type = "SUCCESS", message = null, details = null, dismissable = true, duration = 0, createdDate = null }) {
-        this.id = id;
+    constructor({ type = "SUCCESS", message = null, details = null, dismissable = true, duration = 0, createdDate = null }) {
+        this.id = idSequence++;
         this.type = type;
         this.message = message;
         this.details = details;
diff --git a/django_airavata/static/common/js/notifications/NotificationList.js b/django_airavata/static/common/js/notifications/NotificationList.js
index 09457a7..86c7b41 100644
--- a/django_airavata/static/common/js/notifications/NotificationList.js
+++ b/django_airavata/static/common/js/notifications/NotificationList.js
@@ -1,8 +1,3 @@
-import { errors } from 'django-airavata-api'
-
-import Notification from './Notification'
-
-let notificationIdSequence = 0;
 
 class NotificationList {
 
@@ -22,10 +17,6 @@ class NotificationList {
     get list() {
         return this.notifications;
     }
-
-    getNextId() {
-        return "NOTIFICATION-" + notificationIdSequence++;
-    }
 }
 
 export default new NotificationList();


[airavata-django-portal] 03/05: AIRAVATA-2727 AIRAVATA-2638 Vue global error handler

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit 5e6f01f13aec1cccc84174577443a09ca7ce4a23
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Fri Aug 17 15:21:11 2018 -0400

    AIRAVATA-2727 AIRAVATA-2638 Vue global error handler
---
 .../apps/admin/static/django_airavata_admin/src/main.js  |  3 +--
 .../apps/api/static/django_airavata_api/js/index.js      |  4 ++--
 .../common}/js/errors/GlobalErrorHandler.js              | 16 +++++++++++++---
 django_airavata/static/common/js/index.js                |  6 ++++++
 4 files changed, 22 insertions(+), 7 deletions(-)

diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/main.js b/django_airavata/apps/admin/static/django_airavata_admin/src/main.js
index 46e5ecc..28c151e 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/main.js
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/main.js
@@ -11,8 +11,7 @@ import ComputeResourcePreferenceDashboard from './components/dashboards/ComputeR
 import BootstrapVue from 'bootstrap-vue'
 import 'bootstrap-vue/dist/bootstrap-vue.css'
 
-import { components } from 'django-airavata-common-ui'
-import { errors } from 'django-airavata-api'
+import { components, errors } from 'django-airavata-common-ui'
 
 import router from './router';
 import store from './store/store';
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/index.js b/django_airavata/apps/api/static/django_airavata_api/js/index.js
index ba494bc..2d3aaf4 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/index.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/index.js
@@ -1,5 +1,5 @@
-import GlobalErrorHandler from './errors/GlobalErrorHandler'
 import UnhandledError from './errors/UnhandledError'
+import UnhandledErrorDispatcher from './errors/UnhandledErrorDispatcher'
 import UnhandledErrorDisplayList from './errors/UnhandledErrorDisplayList'
 
 import ApplicationInterfaceDefinition from './models/ApplicationInterfaceDefinition'
@@ -45,8 +45,8 @@ import FetchUtils from './utils/FetchUtils'
 import PaginationIterator from './utils/PaginationIterator'
 
 exports.errors = {
-    GlobalErrorHandler,
     UnhandledError,
+    UnhandledErrorDispatcher,
     UnhandledErrorDisplayList,
 }
 
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/errors/GlobalErrorHandler.js b/django_airavata/static/common/js/errors/GlobalErrorHandler.js
similarity index 50%
rename from django_airavata/apps/api/static/django_airavata_api/js/errors/GlobalErrorHandler.js
rename to django_airavata/static/common/js/errors/GlobalErrorHandler.js
index 02b5278..a3b3f19 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/errors/GlobalErrorHandler.js
+++ b/django_airavata/static/common/js/errors/GlobalErrorHandler.js
@@ -1,16 +1,17 @@
-// import StackTrace from 'stacktrace-js'
 
-import UnhandledErrorDispatcher from './UnhandledErrorDispatcher'
+import Vue from 'vue'
+import { errors } from 'django-airavata-api'
 
 class GlobalErrorHandler {
 
     init() {
         console.log("Initializing GlobalErrorHandler...");
         window.onerror = this.handleGlobalError;
+        Vue.config.errorHandler = this.vueGlobalErrorHandler;
     }
 
     handleGlobalError(msg, url, lineNo, columnNo, error) {
-        UnhandledErrorDispatcher.reportError({
+        errors.UnhandledErrorDispatcher.reportError({
             message: msg,
             error: error,
             details: {
@@ -22,6 +23,15 @@ class GlobalErrorHandler {
 
         return false;
     }
+
+    vueGlobalErrorHandler(err, vm, info) {
+        console.log("Vue Global Error Handler", err, vm, info);
+        errors.UnhandledErrorDispatcher.reportError({
+            message: err.message,
+            error: err,
+            details: info,
+        });
+    }
 }
 
 export default new GlobalErrorHandler()
diff --git a/django_airavata/static/common/js/index.js b/django_airavata/static/common/js/index.js
index 28a2cfa..30b0672 100644
--- a/django_airavata/static/common/js/index.js
+++ b/django_airavata/static/common/js/index.js
@@ -5,6 +5,8 @@ import NotificationsDisplay from './components/NotificationsDisplay.vue'
 import Pager from './components/Pager.vue'
 import ShareButton from './components/ShareButton.vue'
 
+import GlobalErrorHandler from './errors/GlobalErrorHandler'
+
 import ListLayout from './layouts/ListLayout.vue'
 
 import * as utils from './utils'
@@ -18,6 +20,10 @@ exports.components = {
     ShareButton,
 }
 
+exports.errors = {
+    GlobalErrorHandler,
+}
+
 exports.layouts = {
     ListLayout,
 }


[airavata-django-portal] 02/05: AIRAVATA-2727 Handle uncaught TExceptions

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit ceb0b5bcaad38ff50fc5c1b18ad21b65d2b32217
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Fri Aug 17 14:34:15 2018 -0400

    AIRAVATA-2727 Handle uncaught TExceptions
---
 django_airavata/apps/api/exceptions.py                             | 7 +++++--
 .../static/common/js/components/NotificationsDisplay.vue           | 2 +-
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/django_airavata/apps/api/exceptions.py b/django_airavata/apps/api/exceptions.py
index 4075189..632d97c 100644
--- a/django_airavata/apps/api/exceptions.py
+++ b/django_airavata/apps/api/exceptions.py
@@ -4,6 +4,7 @@ import logging
 from rest_framework import serializers, status
 from rest_framework.response import Response
 from rest_framework.views import exception_handler
+from thrift.Thrift import TException
 
 from airavata.api.error.ttypes import AiravataSystemException
 
@@ -15,8 +16,10 @@ def custom_exception_handler(exc, context):
     # to get the standard error response.
     response = exception_handler(exc, context)
 
-    if isinstance(exc, AiravataSystemException):
-        log.error("AiravataSystemException", exc_info=exc)
+    # Default TException handler, should come after more specific subclasses of
+    # TException
+    if isinstance(exc, TException):
+        log.error("TException", exc_info=exc)
         return Response(
             {'detail': str(exc)},
             status=status.HTTP_500_INTERNAL_SERVER_ERROR)
diff --git a/django_airavata/static/common/js/components/NotificationsDisplay.vue b/django_airavata/static/common/js/components/NotificationsDisplay.vue
index 6a71aac..d725d6c 100644
--- a/django_airavata/static/common/js/components/NotificationsDisplay.vue
+++ b/django_airavata/static/common/js/components/NotificationsDisplay.vue
@@ -47,7 +47,7 @@ export default {
             NotificationList.remove(notification);
         },
         dismissedError: function(error) {
-            errors.UnhandledErrorList.remove(error.details);
+            errors.UnhandledErrorDisplayList.remove(error.details);
         },
         variant: function(notification) {
             if (notification.type === "SUCCESS") {


[airavata-django-portal] 04/05: AIRAVATA-2727 Removing TODOs

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit fd7c1d5f45113b38a7cbc7920391bbff4e25fe5c
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Fri Aug 17 15:21:38 2018 -0400

    AIRAVATA-2727 Removing TODOs
---
 .../admin/group_resource_preferences/ComputePreference.vue  | 12 ------------
 .../GroupComputeResourcePreference.vue                      | 13 ++-----------
 .../dashboards/ComputeResourcePreferenceDashboard.vue       |  8 ++------
 3 files changed, 4 insertions(+), 29 deletions(-)

diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputePreference.vue b/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputePreference.vue
index a43a971..0146a92 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputePreference.vue
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/ComputePreference.vue
@@ -211,10 +211,6 @@
                   id: this.id
                 }
               });
-            })
-            .catch(error => {
-              // TODO: handle error
-              console.log("Error occurred", error);
             });
         } else {
           DjangoAiravataAPI.services.ServiceFactory.service("GroupResourceProfiles").create({data: groupResourceProfile})
@@ -226,10 +222,6 @@
                   id: groupResourceProfile.groupResourceProfileId
                 }
               });
-            })
-            .catch(error => {
-              // TODO: handle error
-              console.log("Error occurred", error);
             });
         }
       },
@@ -247,10 +239,6 @@
                   id: this.id
                 }
               });
-            })
-            .catch(error => {
-              // TODO: handle error
-              console.log("Error occurred", error);
             });
         } else {
           // Since nothing was removed, just handle this like a cancel
diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/GroupComputeResourcePreference.vue b/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/GroupComputeResourcePreference.vue
index 206661e..8699553 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/GroupComputeResourcePreference.vue
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/admin/group_resource_preferences/GroupComputeResourcePreference.vue
@@ -147,7 +147,6 @@
               return this.$refs.shareButton.mergeAndSave(groupResourceProfileId);
             });
         }
-        // TODO: handle errors
         persist.then(data => {
           this.$router.push('/group-resource-profiles');
         });
@@ -192,21 +191,13 @@
         let groupResourceProfile = this.data.clone();
         groupResourceProfile.removeComputeResource(computeResourceId);
         this.service.update({data: groupResourceProfile, lookup: this.id})
-          .then(groupResourceProfile => this.data = groupResourceProfile)
-          .catch(error => {
-            // TODO: handle error
-            console.log("Error occurred", error);
-          });
+          .then(groupResourceProfile => this.data = groupResourceProfile);
       },
       removeGroupResourceProfile: function() {
         if (this.id) {
           this.service.delete({lookup: this.id})
             .then(() => {
               this.$router.push('/group-resource-profiles');
-            })
-            .catch(error => {
-              // TODO: handle error
-              console.log("Error occurred", error);
             });
         } else {
           // Nothing to delete so just treat like a cancel
@@ -215,4 +206,4 @@
       }
     },
   }
-</script>
\ No newline at end of file
+</script>
diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/components/dashboards/ComputeResourcePreferenceDashboard.vue b/django_airavata/apps/admin/static/django_airavata_admin/src/components/dashboards/ComputeResourcePreferenceDashboard.vue
index bddae9a..a4548bd 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/components/dashboards/ComputeResourcePreferenceDashboard.vue
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/components/dashboards/ComputeResourcePreferenceDashboard.vue
@@ -73,15 +73,11 @@
 
         services.GroupResourceProfileService.delete({lookup: groupResourceProfile.groupResourceProfileId})
           .then(() => services.GroupResourceProfileService.list())
-          .then(groupResourceProfiles => this.groupResourceProfiles = groupResourceProfiles)
-          .catch(error => {
-            // TODO: handle error
-            console.log("Error occurred", error);
-          });
+          .then(groupResourceProfiles => this.groupResourceProfiles = groupResourceProfiles);
       }
     },
     mounted: function () {
       this.loadGroupResourceProfiles();
     }
   }
-</script>
\ No newline at end of file
+</script>


[airavata-django-portal] 01/05: AIRAVATA-2727 AIRAVATA-2638 Global error handling

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit 7545f270dd311b80a3d8ac8b1439e0b95054e4fa
Author: Marcus Christie <ma...@iu.edu>
AuthorDate: Fri Aug 17 14:29:16 2018 -0400

    AIRAVATA-2727 AIRAVATA-2638 Global error handling
---
 .../admin/static/django_airavata_admin/src/main.js |  10 +-
 django_airavata/apps/api/exceptions.py             |  30 ++
 django_airavata/apps/api/serializers.py            |  12 +-
 .../django_airavata_api/js/errors/ErrorReporter.js |   9 +
 .../js/errors/GlobalErrorHandler.js                |  27 ++
 .../js/errors/UnhandledError.js                    |  19 +
 .../js/errors/UnhandledErrorDispatcher.js          |  18 +
 .../js/errors/UnhandledErrorDisplayList.js         |  21 +
 .../api/static/django_airavata_api/js/index.js     |  12 +-
 .../js/services/ServiceFactory.js                  |  12 +-
 .../django_airavata_api/js/utils/FetchUtils.js     | 133 ++++---
 django_airavata/apps/api/thrift_utils.py           |   8 +-
 django_airavata/apps/api/views.py                  |   4 +-
 django_airavata/settings.py                        |   2 +
 .../common/js/components/NotificationsDisplay.vue  |  75 ++++
 django_airavata/static/common/js/index.js          |   2 +
 .../static/common/js/notifications/Notification.js |  14 +
 .../common/js/notifications/NotificationList.js    |  31 ++
 django_airavata/static/common/package-lock.json    | 424 +++++----------------
 19 files changed, 460 insertions(+), 403 deletions(-)

diff --git a/django_airavata/apps/admin/static/django_airavata_admin/src/main.js b/django_airavata/apps/admin/static/django_airavata_admin/src/main.js
index fa8a27b..46e5ecc 100644
--- a/django_airavata/apps/admin/static/django_airavata_admin/src/main.js
+++ b/django_airavata/apps/admin/static/django_airavata_admin/src/main.js
@@ -11,9 +11,14 @@ import ComputeResourcePreferenceDashboard from './components/dashboards/ComputeR
 import BootstrapVue from 'bootstrap-vue'
 import 'bootstrap-vue/dist/bootstrap-vue.css'
 
+import { components } from 'django-airavata-common-ui'
+import { errors } from 'django-airavata-api'
+
 import router from './router';
 import store from './store/store';
 
+errors.GlobalErrorHandler.init();
+
 Vue.config.productionTip = false;
 
 Vue.use(BootstrapVue)
@@ -23,7 +28,7 @@ Vue.use(VueRouter);
 
 export function initializeApacheAiravataDashboard(dashboardName) {
   var template = `
-    <div class="vmain"><Loading/> 
+    <div class="vmain"><notifications-display/><Loading/> 
         <transition name="fade">
             <router-view>
             </router-view>
@@ -40,7 +45,8 @@ export function initializeApacheAiravataDashboard(dashboardName) {
       CredentialStore,
       Loading,
       ComputeResourceDashboard,
-      ComputeResourcePreferenceDashboard
+      ComputeResourcePreferenceDashboard,
+      'notifications-display': components.NotificationsDisplay,
     },
     mounted:function () {
       if (this.$router.currentRoute.path === '/') {
diff --git a/django_airavata/apps/api/exceptions.py b/django_airavata/apps/api/exceptions.py
new file mode 100644
index 0000000..4075189
--- /dev/null
+++ b/django_airavata/apps/api/exceptions.py
@@ -0,0 +1,30 @@
+import json
+import logging
+
+from rest_framework import serializers, status
+from rest_framework.response import Response
+from rest_framework.views import exception_handler
+
+from airavata.api.error.ttypes import AiravataSystemException
+
+log = logging.getLogger(__name__)
+
+
+def custom_exception_handler(exc, context):
+    # Call REST framework's default exception handler first,
+    # to get the standard error response.
+    response = exception_handler(exc, context)
+
+    if isinstance(exc, AiravataSystemException):
+        log.error("AiravataSystemException", exc_info=exc)
+        return Response(
+            {'detail': str(exc)},
+            status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+    if isinstance(exc, serializers.ValidationError):
+        # Create a default error message for the validation error
+        response.data['detail'] = "ValidationError: {}".format(
+            json.dumps(response.data))
+
+    log.debug("API exception", exc_info=exc)
+    return response
diff --git a/django_airavata/apps/api/serializers.py b/django_airavata/apps/api/serializers.py
index a174565..585f9c6 100644
--- a/django_airavata/apps/api/serializers.py
+++ b/django_airavata/apps/api/serializers.py
@@ -44,7 +44,14 @@ class FullyEncodedHyperlinkedIdentityField(serializers.HyperlinkedIdentityField)
             lookup_value = getattr(obj, self.lookup_field)
         else:
             lookup_value = obj.get(self.lookup_field)
-        encoded_lookup_value = quote(lookup_value, safe="")
+        try:
+            encoded_lookup_value = quote(lookup_value, safe="")
+        except Exception as e:
+            log.warning(
+                "Failed to encode lookup_value [{}] for lookup_field "
+                "[{}] of object [{}]".format(
+                    lookup_value, self.lookup_field, obj))
+            raise
         # Bit of a hack. Django's URL reversing does URL encoding but it doesn't
         # encode all characters including some like '/' that are used in URL
         # mappings.
@@ -451,6 +458,9 @@ class GroupResourceProfileSerializer(
     updatedTime = UTCPosixTimestampDateTimeField(allow_null=True)
     userHasWriteAccess = serializers.SerializerMethodField()
 
+    class Meta:
+        required = ('groupResourceProfileName',)
+
     def update(self, instance, validated_data):
         result = super().update(instance, validated_data)
         result._removed_compute_resource_preferences = []
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/errors/ErrorReporter.js b/django_airavata/apps/api/static/django_airavata_api/js/errors/ErrorReporter.js
new file mode 100644
index 0000000..7dc83e2
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/errors/ErrorReporter.js
@@ -0,0 +1,9 @@
+
+class ErrorReporter {
+    reportUnhandledError(unhandledError) {
+        // TODO: send to the server so it can be logged there
+        console.log(JSON.stringify(unhandledError, null, 4));
+    }
+}
+
+export default new ErrorReporter();
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/errors/GlobalErrorHandler.js b/django_airavata/apps/api/static/django_airavata_api/js/errors/GlobalErrorHandler.js
new file mode 100644
index 0000000..02b5278
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/errors/GlobalErrorHandler.js
@@ -0,0 +1,27 @@
+// import StackTrace from 'stacktrace-js'
+
+import UnhandledErrorDispatcher from './UnhandledErrorDispatcher'
+
+class GlobalErrorHandler {
+
+    init() {
+        console.log("Initializing GlobalErrorHandler...");
+        window.onerror = this.handleGlobalError;
+    }
+
+    handleGlobalError(msg, url, lineNo, columnNo, error) {
+        UnhandledErrorDispatcher.reportError({
+            message: msg,
+            error: error,
+            details: {
+                url,
+                lineNo,
+                columnNo
+            }
+        });
+
+        return false;
+    }
+}
+
+export default new GlobalErrorHandler()
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/errors/UnhandledError.js b/django_airavata/apps/api/static/django_airavata_api/js/errors/UnhandledError.js
new file mode 100644
index 0000000..33a80ae
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/errors/UnhandledError.js
@@ -0,0 +1,19 @@
+
+let idSequence = 0;
+class UnhandledError {
+    constructor({message = null, error = null, details = null, suppressDisplay = false, suppressLogging = false}) {
+        this.id = idSequence++;
+        this.message = message;
+        this.error = error;
+        this.details = details;
+        this.suppressDisplay = suppressDisplay;
+        this.suppressLogging = suppressLogging;
+        this.createdDate = new Date();
+    }
+
+    get displayMessage() {
+        return this.error && this.error.message ? this.error.message : this.message;
+    }
+}
+
+export default UnhandledError;
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/errors/UnhandledErrorDispatcher.js b/django_airavata/apps/api/static/django_airavata_api/js/errors/UnhandledErrorDispatcher.js
new file mode 100644
index 0000000..1a8cee5
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/errors/UnhandledErrorDispatcher.js
@@ -0,0 +1,18 @@
+import ErrorReporter from './ErrorReporter'
+import UnhandledError from './UnhandledError'
+import UnhandledErrorList from './UnhandledErrorDisplayList';
+
+class UnhandledErrorDispatcher {
+
+    reportError({ message = null, error = null, details = null, suppressDisplay = false, suppressLogging = false }) {
+        const unhandledError = new UnhandledError({message, error, details, suppressDisplay, suppressLogging});
+        if (!unhandledError.suppressDisplay) {
+            UnhandledErrorList.add(unhandledError);
+        }
+        if (!unhandledError.suppressLogging) {
+            ErrorReporter.reportUnhandledError(unhandledError);
+        }
+    }
+}
+
+export default new UnhandledErrorDispatcher();
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/errors/UnhandledErrorDisplayList.js b/django_airavata/apps/api/static/django_airavata_api/js/errors/UnhandledErrorDisplayList.js
new file mode 100644
index 0000000..411beb9
--- /dev/null
+++ b/django_airavata/apps/api/static/django_airavata_api/js/errors/UnhandledErrorDisplayList.js
@@ -0,0 +1,21 @@
+
+class UnhandledErrorDisplayList {
+    constructor() {
+        this.unhandledErrors = [];
+    }
+
+    add(unhandledError) {
+        this.unhandledErrors.push(unhandledError);
+    }
+
+    remove(unhandledError) {
+        const i = this.unhandledErrors.indexOf(unhandledError);
+        this.unhandledErrors.splice(i, 1);
+    }
+
+    get list() {
+        return this.unhandledErrors;
+    }
+}
+
+export default new UnhandledErrorDisplayList();
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/index.js b/django_airavata/apps/api/static/django_airavata_api/js/index.js
index 0e3502b..ba494bc 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/index.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/index.js
@@ -1,3 +1,6 @@
+import GlobalErrorHandler from './errors/GlobalErrorHandler'
+import UnhandledError from './errors/UnhandledError'
+import UnhandledErrorDisplayList from './errors/UnhandledErrorDisplayList'
 
 import ApplicationInterfaceDefinition from './models/ApplicationInterfaceDefinition'
 import ApplicationModule from './models/ApplicationModule'
@@ -28,7 +31,6 @@ import ExperimentSearchService from './services/ExperimentSearchService'
 import FullExperimentService from './services/FullExperimentService'
 import ProjectService from './services/ProjectService'
 import GroupService from './services/GroupService'
-import GroupResourceProfileService from './services/GroupResourceProfileService'
 import UserProfileService from './services/UserProfileService'
 import CloudJobSubmissionService from './services/CloudJobSubmissionService'
 import GlobusJobSubmissionService from './services/GlobusJobSubmissionService'
@@ -42,6 +44,12 @@ import ServiceFactory from './services/ServiceFactory'
 import FetchUtils from './utils/FetchUtils'
 import PaginationIterator from './utils/PaginationIterator'
 
+exports.errors = {
+    GlobalErrorHandler,
+    UnhandledError,
+    UnhandledErrorDisplayList,
+}
+
 exports.models = {
     ApplicationInterfaceDefinition,
     ApplicationModule,
@@ -86,7 +94,7 @@ exports.services = {
     GridFTPDataMovementService,
     SCPDataMovementService,
     UnicoreDataMovementService,
-    ServiceFactory
+    ServiceFactory,
 }
 
 exports.utils = {
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/services/ServiceFactory.js b/django_airavata/apps/api/static/django_airavata_api/js/services/ServiceFactory.js
index 6ab85b5..7d9d408 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/services/ServiceFactory.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/services/ServiceFactory.js
@@ -159,7 +159,7 @@ class ServiceFactory {
             }
             let pathParamsMapping = parsePathParams(config.url);
             let queryParamsMapping = parseQueryMapping(config.queryParams);
-            serviceObj[functionName] = function (params = {}) {
+            serviceObj[functionName] = function (params = {}, { ignoreErrors } = { ignoreErrors: false }) {
                 let url = config.url;
                 let paramKeys = Object.keys(params);
                 let queryParams = {};
@@ -198,13 +198,13 @@ class ServiceFactory {
                 }
                 switch (config.requestType.toLowerCase()) {
                     case postKey:
-                        return FetchUtils.post(url, bodyParams, queryParams).then(resultHandler);
+                        return FetchUtils.post(url, bodyParams, queryParams, { ignoreErrors }).then(resultHandler);
                     case getKey:
-                        return FetchUtils.get(url, queryParams).then(paginationHandler);
+                        return FetchUtils.get(url, queryParams, { ignoreErrors }).then(paginationHandler);
                     case putKey:
-                        return FetchUtils.put(url, bodyParams).then(resultHandler);
+                        return FetchUtils.put(url, bodyParams, { ignoreErrors }).then(resultHandler);
                     case delKey:
-                        return FetchUtils.delete(url);
+                        return FetchUtils.delete(url, { ignoreErrors });
                 }
             }
         }
@@ -212,4 +212,4 @@ class ServiceFactory {
     }
 }
 
-export default new ServiceFactory(serviceConfiguration);
\ No newline at end of file
+export default new ServiceFactory(serviceConfiguration);
diff --git a/django_airavata/apps/api/static/django_airavata_api/js/utils/FetchUtils.js b/django_airavata/apps/api/static/django_airavata_api/js/utils/FetchUtils.js
index 7395690..f16d382 100644
--- a/django_airavata/apps/api/static/django_airavata_api/js/utils/FetchUtils.js
+++ b/django_airavata/apps/api/static/django_airavata_api/js/utils/FetchUtils.js
@@ -1,3 +1,5 @@
+import UnhandledErrorDispatcher from "../errors/UnhandledErrorDispatcher";
+
 var count = 0;
 const parseQueryParams = function (url, queryParams = "") {
     if (queryParams && typeof(queryParams) != "string") {
@@ -56,61 +58,31 @@ export default {
         }
         return headers;
     },
-    post: function (url, body, queryParams = "", mediaType = "application/json") {
+    post: function (url, body, queryParams = "", {mediaType = "application/json", ignoreErrors = false } = {}) {
         var headers = this.createHeaders(mediaType)
         // Browsers automatically handle content type for FormData request bodies
         if (body instanceof FormData) {
             headers.delete("Content-Type");
         }
-        console.log("post body", body);
         url = parseQueryParams(url, queryParams);
-        incrementCount();
-        return fetch(url, {
+        return this.processFetch(url, {
             method: 'post',
             body: (body instanceof FormData || typeof body === 'string') ? body : JSON.stringify(body),
             headers: headers,
-            credentials: "same-origin"
-        }).then((response) => {
-            decrementCount();
-            if (response.ok) {
-                return Promise.resolve(response.json())
-            } else {
-                let error = new Error(response.statusText);
-                return response.json().then(json => {
-                    error.data = json;
-                })
-                    .then(() => Promise.reject(error), () => Promise.reject(error));
-            }
-        }, (response) => {
-            decrementCount();
-            return Promise.reject(response);
-        })
+            credentials: "same-origin",
+            ignoreErrors
+        });
     },
-    put: function (url, body, mediaType = "application/json") {
+    put: function (url, body, { mediaType = "application/json", ignoreErrors = false } = {}) {
         var headers = this.createHeaders(mediaType);
-        incrementCount();
-        return fetch(url, {
+        return this.processFetch(url, {
             method: 'put',
             body: (body instanceof FormData || typeof body === 'string') ? body : JSON.stringify(body),
             headers: headers,
             credentials: "same-origin"
-        }).then((response) => {
-            decrementCount();
-            if (response.ok) {
-                return Promise.resolve(response.json())
-            } else {
-                let error = new Error(response.statusText);
-                return response.json().then(json => {
-                    error.data = json;
-                })
-                    .then(() => Promise.reject(error), () => Promise.reject(error));
-            }
-        }, (response) => {
-            decrementCount();
-            return Promise.reject(response);
-        })
+        });
     },
-    get: function (url, queryParams = "", mediaType = "application/json") {
+    get: function (url, queryParams = "", { mediaType = "application/json", ignoreErrors = false } = {}) {
         if (queryParams && typeof(queryParams) != "string") {
             queryParams = Object.keys(queryParams).map(key => encodeURIComponent(key) + "=" + encodeURIComponent(queryParams[key])).join("&")
         }
@@ -118,46 +90,73 @@ export default {
             url = url + "?" + queryParams
         }
         var headers = this.createHeaders(mediaType);
-        incrementCount();
-        return fetch(url, {
+        return this.processFetch(url, {
             method: 'get',
             headers: headers,
             credentials: "same-origin"
-        }).then((response) => {
-            decrementCount();
-            if (response.ok) {
-                return Promise.resolve(response.json())
-            } else {
-                let error = new Error(response.statusText);
-                return response.json().then(json => {
-                    error.data = json;
-                })
-                    .then(() => Promise.reject(error), () => Promise.reject(error));
-            }
-        }, (response) => {
-            decrementCount();
-            return Promise.reject(response);
-        })
+        });
     },
-    delete: function (url) {
+    delete: function (url, { ignoreErrors = false } = {}) {
         var headers = this.createHeaders();
-        incrementCount();
-        return fetch(url, {
+        return this.processFetch(url, {
             method: 'delete',
             headers: headers,
             credentials: "same-origin"
-        }).then((response) => {
+        });
+    },
+    processFetch: function(url, {method = 'get', headers, credentials = 'same-origin', body, ignoreErrors = false}) {
+
+        const fetchConfig = {
+            method,
+            headers,
+            credentials,
+        };
+        if (body) {
+            fetchConfig.body = body;
+        }
+        incrementCount();
+        return fetch(url, fetchConfig).then((response) => {
             decrementCount();
-            // Not expecting a response body
-            if (response.ok && response.status === 204) {
-                return Promise.resolve();
+            if (response.ok) {
+                // No response body
+                if (response.status === 204) {
+                    return Promise.resolve();
+                } else {
+                    return Promise.resolve(response.json())
+                }
             } else {
-                let error = new Error(response.statusText);
                 return response.json().then(json => {
-                    error.data = json;
+                    const error = new Error(json.detail ? json.detail : response.statusText);
+                    error.details = this.createErrorDetails({url, body, status: response.status, responseBody: json})
+                    throw error;
+                }, e => { // In case JSON parsing fails
+                    const error = new Error(response.statusText);
+                    error.details = this.createErrorDetails({url, body, status: response.status})
+                    throw error;
+                });
+            }
+        }, (error) => {
+            decrementCount();
+            error.details = this.createErrorDetails({url, body});
+            throw error;
+        }).catch(error => {
+
+            if (!ignoreErrors) {
+                UnhandledErrorDispatcher.reportError({
+                    message: error.message,
+                    error: error,
+                    details: error.details,
                 })
-                    .then(() => Promise.reject(error), () => Promise.reject(error));
             }
+            throw error;
         })
+    },
+    createErrorDetails: function({url, body, status = null, responseBody = null}={}) {
+        return {
+            url,
+            body,
+            status,
+            response: responseBody
+        }
     }
-}
\ No newline at end of file
+}
diff --git a/django_airavata/apps/api/thrift_utils.py b/django_airavata/apps/api/thrift_utils.py
index bbff521..be59ab9 100644
--- a/django_airavata/apps/api/thrift_utils.py
+++ b/django_airavata/apps/api/thrift_utils.py
@@ -90,8 +90,12 @@ def create_serializer_class(thrift_data_type, enable_date_time_conversion=False)
             for field in thrift_spec:
                 # Don't replace existing attrs to allow subclasses to override
                 if field and field[2] not in attrs:
-                    required = field[2] in meta.required if meta else False
-                    read_only = field[2] in meta.read_only if meta else False
+                    required = (field[2] in meta.required
+                                if meta and hasattr(meta, 'required')
+                                else False)
+                    read_only = (field[2] in meta.read_only
+                                 if meta and hasattr(meta, 'read_only')
+                                 else False)
                     allow_null = not required
                     field_serializer = process_field(
                         field, enable_date_time_conversion, required=required, read_only=read_only,
diff --git a/django_airavata/apps/api/views.py b/django_airavata/apps/api/views.py
index f3b4359..2edcae0 100644
--- a/django_airavata/apps/api/views.py
+++ b/django_airavata/apps/api/views.py
@@ -693,9 +693,7 @@ class GroupResourceProfileViewSet(APIBackedViewSet):
         group_resource_profile.gatewayId = self.gateway_id
         group_resource_profile_id = self.request.airavata_client.createGroupResourceProfile(authzToken=self.authz_token,
                                                                                             groupResourceProfile=group_resource_profile)
-        group_resource_profile = self.request.airavata_client.getGroupResourceProfile(
-            self.authz_token, group_resource_profile_id)
-        serializer.instance = group_resource_profile
+        group_resource_profile.groupResourceProfileId = group_resource_profile_id
 
     def perform_update(self, serializer):
         grp = serializer.save()
diff --git a/django_airavata/settings.py b/django_airavata/settings.py
index 2748bc7..ed05acf 100644
--- a/django_airavata/settings.py
+++ b/django_airavata/settings.py
@@ -174,6 +174,8 @@ REST_FRAMEWORK = {
     'DEFAULT_PERMISSION_CLASSES': (
         'rest_framework.permissions.IsAuthenticated',
     ),
+    'EXCEPTION_HANDLER':
+        'django_airavata.apps.api.exceptions.custom_exception_handler',
 }
 
 AUTHENTICATION_BACKENDS = [
diff --git a/django_airavata/static/common/js/components/NotificationsDisplay.vue b/django_airavata/static/common/js/components/NotificationsDisplay.vue
new file mode 100644
index 0000000..6a71aac
--- /dev/null
+++ b/django_airavata/static/common/js/components/NotificationsDisplay.vue
@@ -0,0 +1,75 @@
+<template>
+    <div id="notifications-display">
+        <transition-group name="fade" tag="div">
+            <b-alert v-for="error in errors"
+                    :variant="variant(error)" :key="error.id"
+                    show dismissible @dismissed="dismissedError(error)">
+                {{ error.message }}
+            </b-alert>
+            <b-alert v-for="notification in notifications"
+                    :variant="variant(notification)" :key="notification.id"
+                    show dismissible @dismissed="dismissedNotification(notification)">
+                {{ notification.message }}
+            </b-alert>
+        </transition-group>
+    </div>
+</template>
+
+<script>
+
+import { errors } from 'django-airavata-api'
+import Notification from '../notifications/Notification'
+import NotificationList from '../notifications/NotificationList'
+
+export default {
+    name: "notifications-display",
+    data () {
+        return {
+            notifications: NotificationList.list,
+            unhandledErrors: errors.UnhandledErrorDisplayList.list,
+        }
+    },
+    computed: {
+        errors: function() {
+
+            return this.unhandledErrors.map(unhandledError => {
+                return new Notification("UNHANDLED-ERROR-" + unhandledError.id, {
+                    type: "ERROR",
+                    message: unhandledError.displayMessage,
+                    details: unhandledError,
+                    createdDate: unhandledError.createdDate,
+                });
+            })
+        }
+    },
+    methods: {
+        dismissedNotification: function(notification) {
+            NotificationList.remove(notification);
+        },
+        dismissedError: function(error) {
+            errors.UnhandledErrorList.remove(error.details);
+        },
+        variant: function(notification) {
+            if (notification.type === "SUCCESS") {
+                return "success";
+            } else if (notification.type === "ERROR") {
+                return "danger";
+            } else {
+                return "secondary";
+            }
+        }
+    },
+}
+</script>
+
+<style>
+#notifications-display {
+    position: fixed;
+    top: 75px;
+    left: 20vw;
+    width: 60vw;
+    z-index: 10000;
+}
+</style>
+
+
diff --git a/django_airavata/static/common/js/index.js b/django_airavata/static/common/js/index.js
index 9c9c22f..28a2cfa 100644
--- a/django_airavata/static/common/js/index.js
+++ b/django_airavata/static/common/js/index.js
@@ -1,6 +1,7 @@
 import ApplicationCard from './components/ApplicationCard.vue'
 import Autocomplete from './components/Autocomplete.vue'
 import AutocompleteTextInput from './components/AutocompleteTextInput.vue'
+import NotificationsDisplay from './components/NotificationsDisplay.vue'
 import Pager from './components/Pager.vue'
 import ShareButton from './components/ShareButton.vue'
 
@@ -13,6 +14,7 @@ exports.components = {
     ApplicationCard,
     Autocomplete,
     AutocompleteTextInput,
+    NotificationsDisplay,
     ShareButton,
 }
 
diff --git a/django_airavata/static/common/js/notifications/Notification.js b/django_airavata/static/common/js/notifications/Notification.js
new file mode 100644
index 0000000..1b8864e
--- /dev/null
+++ b/django_airavata/static/common/js/notifications/Notification.js
@@ -0,0 +1,14 @@
+
+class Notification {
+    constructor(id, { type = "SUCCESS", message = null, details = null, dismissable = true, duration = 0, createdDate = null }) {
+        this.id = id;
+        this.type = type;
+        this.message = message;
+        this.details = details;
+        this.dismissable = dismissable;
+        this.duration = duration;
+        this.createdDate = createdDate ? createdDate : new Date();
+    }
+}
+
+export default Notification;
diff --git a/django_airavata/static/common/js/notifications/NotificationList.js b/django_airavata/static/common/js/notifications/NotificationList.js
new file mode 100644
index 0000000..09457a7
--- /dev/null
+++ b/django_airavata/static/common/js/notifications/NotificationList.js
@@ -0,0 +1,31 @@
+import { errors } from 'django-airavata-api'
+
+import Notification from './Notification'
+
+let notificationIdSequence = 0;
+
+class NotificationList {
+
+    constructor() {
+        this.notifications = [];
+    }
+
+    add(notification) {
+        this.notifications.push(notification);
+    }
+
+    remove(notification) {
+        const i = this.notifications.indexOf(notification);
+        this.notifications.splice(i, 1);
+    }
+
+    get list() {
+        return this.notifications;
+    }
+
+    getNextId() {
+        return "NOTIFICATION-" + notificationIdSequence++;
+    }
+}
+
+export default new NotificationList();
diff --git a/django_airavata/static/common/package-lock.json b/django_airavata/static/common/package-lock.json
index 564d5ff..664d58a 100644
--- a/django_airavata/static/common/package-lock.json
+++ b/django_airavata/static/common/package-lock.json
@@ -213,10 +213,13 @@
       "dev": true
     },
     "asn1": {
-      "version": "0.2.3",
-      "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
-      "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=",
-      "dev": true
+      "version": "0.2.4",
+      "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
+      "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
+      "dev": true,
+      "requires": {
+        "safer-buffer": "~2.1.0"
+      }
     },
     "asn1.js": {
       "version": "4.10.1",
@@ -256,9 +259,9 @@
       }
     },
     "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=",
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
+      "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
       "dev": true
     },
     "assign-symbols": {
@@ -327,15 +330,15 @@
       }
     },
     "aws-sign2": {
-      "version": "0.6.0",
-      "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz",
-      "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=",
+      "version": "0.7.0",
+      "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
+      "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
       "dev": true
     },
     "aws4": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz",
-      "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==",
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
+      "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
       "dev": true
     },
     "babel-code-frame": {
@@ -1140,15 +1143,6 @@
         "multicast-dns-service-types": "^1.1.0"
       }
     },
-    "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.x.x"
-      }
-    },
     "bootstrap": {
       "version": "4.1.3",
       "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.1.3.tgz",
@@ -1390,15 +1384,15 @@
       }
     },
     "caniuse-db": {
-      "version": "1.0.30000872",
-      "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000872.tgz",
-      "integrity": "sha1-P25Ttj03N2i/meiWEz1m74nEmZk=",
+      "version": "1.0.30000877",
+      "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000877.tgz",
+      "integrity": "sha512-9RcqvE8HYgdZZzFW6xBmj/CeCaTyCJdUhgkueBCq47AK//w/Yzlg0zcfV1GTlh3jyYEbresGfY2vDEG/AaK/dQ==",
       "dev": true
     },
     "caniuse-lite": {
-      "version": "1.0.30000865",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000865.tgz",
-      "integrity": "sha512-vs79o1mOSKRGv/1pSkp4EXgl4ZviWeYReXw60XfacPU64uQWZwJT6vZNmxRF9O+6zu71sJwMxLK5JXxbzuVrLw==",
+      "version": "1.0.30000877",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000877.tgz",
+      "integrity": "sha512-h04kV/lcuhItU1CZTJOxUEk/9R+1XeJqgc67E+XC8J9TjPM8kzVgOn27ZtRdDUo8O5F8U4QRCzDWJrVym3w3Cg==",
       "dev": true
     },
     "caseless": {
@@ -1654,9 +1648,9 @@
       }
     },
     "commander": {
-      "version": "2.16.0",
-      "resolved": "https://registry.npmjs.org/commander/-/commander-2.16.0.tgz",
-      "integrity": "sha512-sVXqklSaotK9at437sFlFpyOcJonxe0yST/AG9DkQKUdIE6IqGIMv4SfAQSKaJbSdVEJYItASCrBiVQHq1HQew==",
+      "version": "2.17.1",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
+      "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==",
       "dev": true
     },
     "commondir": {
@@ -1867,15 +1861,6 @@
         "which": "^1.2.9"
       }
     },
-    "cryptiles": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz",
-      "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=",
-      "dev": true,
-      "requires": {
-        "boom": "2.x.x"
-      }
-    },
     "crypto-browserify": {
       "version": "3.12.0",
       "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
@@ -2040,14 +2025,6 @@
       "dev": 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
-        }
       }
     },
     "date-now": {
@@ -2090,13 +2067,12 @@
       "dev": true
     },
     "define-properties": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz",
-      "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=",
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
+      "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==",
       "dev": true,
       "requires": {
-        "foreach": "^2.0.5",
-        "object-keys": "^1.0.8"
+        "object-keys": "^1.0.12"
       }
     },
     "define-property": {
@@ -4044,15 +4020,15 @@
       "dev": true
     },
     "electron-to-chromium": {
-      "version": "1.3.55",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.55.tgz",
-      "integrity": "sha1-8VDhCyC3fZ1Br8yjEu/gw7Gn/c4=",
+      "version": "1.3.58",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.58.tgz",
+      "integrity": "sha512-AGJxlBEn2wOohxqWZkISVsOjZueKTQljfEODTDSEiMqSpH0S+xzV+/5oEM9AGaqhu7DzrpKOgU7ocQRjj0nJmg==",
       "dev": true
     },
     "elliptic": {
-      "version": "6.4.0",
-      "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz",
-      "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=",
+      "version": "6.4.1",
+      "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz",
+      "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==",
       "dev": true,
       "requires": {
         "bn.js": "^4.4.0",
@@ -4139,9 +4115,9 @@
       }
     },
     "es5-ext": {
-      "version": "0.10.45",
-      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.45.tgz",
-      "integrity": "sha512-FkfM6Vxxfmztilbxxz5UKSD4ICMf5tSpRFtDNtkAhOxZ0EKtX6qwmXNyH/sFyIbX2P/nU5AMiA9jilWsUGJzCQ==",
+      "version": "0.10.46",
+      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.46.tgz",
+      "integrity": "sha512-24XxRvJXNFwEMpJb3nOkiRJKRoupmjYmOPVlI65Qy2SrtxwOTB+g6ODjBKOtwEHbYrhWRty9xxOWLNdClT2djw==",
       "dev": true,
       "requires": {
         "es6-iterator": "~2.0.3",
@@ -4714,9 +4690,9 @@
       "dev": true
     },
     "follow-redirects": {
-      "version": "1.5.2",
-      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.2.tgz",
-      "integrity": "sha512-kssLorP/9acIdpQ2udQVTiCS5LQmdEz9mvdIfDcl1gYX2tPKFADHSyFdvJS040XdFsPzemWtgI3q8mFVCxtX8A==",
+      "version": "1.5.5",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.5.tgz",
+      "integrity": "sha512-GHjtHDlY/ehslqv0Gr5N0PUJppgg/q0rOBvX0na1s7y1A3LWxPqCYU76s3Z1bM4+UZB4QF0usaXLT5wFpof5PA==",
       "dev": true,
       "requires": {
         "debug": "^3.1.0"
@@ -4748,12 +4724,6 @@
         "for-in": "^1.0.1"
       }
     },
-    "foreach": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
-      "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=",
-      "dev": true
-    },
     "forever-agent": {
       "version": "0.6.1",
       "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
@@ -4761,13 +4731,13 @@
       "dev": true
     },
     "form-data": {
-      "version": "2.1.4",
-      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz",
-      "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=",
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
+      "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
       "dev": true,
       "requires": {
         "asynckit": "^0.4.0",
-        "combined-stream": "^1.0.5",
+        "combined-stream": "1.0.6",
         "mime-types": "^2.1.12"
       }
     },
@@ -5423,14 +5393,6 @@
       "dev": 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
-        }
       }
     },
     "glob": {
@@ -5555,31 +5517,19 @@
       "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=",
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
+      "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
       "dev": true
     },
     "har-validator": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz",
-      "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=",
+      "version": "5.0.3",
+      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
+      "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
       "dev": true,
       "requires": {
-        "ajv": "^4.9.1",
-        "har-schema": "^1.0.5"
-      },
-      "dependencies": {
-        "ajv": {
-          "version": "4.11.8",
-          "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
-          "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
-          "dev": true,
-          "requires": {
-            "co": "^4.6.0",
-            "json-stable-stringify": "^1.0.1"
-          }
-        }
+        "ajv": "^5.1.0",
+        "har-schema": "^2.0.0"
       }
     },
     "has": {
@@ -5669,18 +5619,6 @@
         "minimalistic-assert": "^1.0.1"
       }
     },
-    "hawk": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz",
-      "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=",
-      "dev": true,
-      "requires": {
-        "boom": "2.x.x",
-        "cryptiles": "2.x.x",
-        "hoek": "2.x.x",
-        "sntp": "1.x.x"
-      }
-    },
     "he": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
@@ -5698,12 +5636,6 @@
         "minimalistic-crypto-utils": "^1.0.1"
       }
     },
-    "hoek": {
-      "version": "2.16.3",
-      "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz",
-      "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=",
-      "dev": true
-    },
     "home-or-tmp": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
@@ -5902,12 +5834,12 @@
       }
     },
     "http-signature": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz",
-      "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=",
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
+      "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
       "dev": true,
       "requires": {
-        "assert-plus": "^0.2.0",
+        "assert-plus": "^1.0.0",
         "jsprim": "^1.2.2",
         "sshpk": "^1.7.0"
       }
@@ -6440,15 +6372,6 @@
       "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
       "dev": 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,
-      "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",
@@ -6467,12 +6390,6 @@
       "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
       "dev": true
     },
-    "jsonify": {
-      "version": "0.0.0",
-      "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
-      "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
-      "dev": true
-    },
     "jsprim": {
       "version": "1.4.1",
       "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
@@ -6483,14 +6400,6 @@
         "extsprintf": "1.3.0",
         "json-schema": "0.2.3",
         "verror": "1.10.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
-        }
       }
     },
     "killable": {
@@ -7009,9 +6918,9 @@
       "dev": true
     },
     "neo-async": {
-      "version": "2.5.1",
-      "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.5.1.tgz",
-      "integrity": "sha512-3KL3fvuRkZ7s4IFOMfztb7zJp3QaVWnBeGoJlgB38XnCRPj/0tLzzLG5IB8NYOHbJ8g8UGrgZv44GLDk6CxTxA==",
+      "version": "2.5.2",
+      "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.5.2.tgz",
+      "integrity": "sha512-vdqTKI9GBIYcAEbFAcpKPErKINfPF5zIuz3/niBfq8WUZjpT2tytLlFVrBgWdOtqI4uaA/Rb6No0hux39XXDuw==",
       "dev": true
     },
     "next-tick": {
@@ -7036,9 +6945,9 @@
       "dev": true
     },
     "node-gyp": {
-      "version": "3.7.0",
-      "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.7.0.tgz",
-      "integrity": "sha512-qDQE/Ft9xXP6zphwx4sD0t+VhwV7yFaloMpfbL2QnnDZcyaiakWlLdtFGGQfTAwpFHdpbRhRxVhIHN1OKAjgbg==",
+      "version": "3.8.0",
+      "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
+      "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==",
       "dev": true,
       "requires": {
         "fstream": "^1.0.0",
@@ -7048,43 +6957,13 @@
         "nopt": "2 || 3",
         "npmlog": "0 || 1 || 2 || 3 || 4",
         "osenv": "0",
-        "request": ">=2.9.0 <2.82.0",
+        "request": "^2.87.0",
         "rimraf": "2",
         "semver": "~5.3.0",
         "tar": "^2.0.0",
         "which": "1"
       },
       "dependencies": {
-        "request": {
-          "version": "2.81.0",
-          "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz",
-          "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=",
-          "dev": true,
-          "requires": {
-            "aws-sign2": "~0.6.0",
-            "aws4": "^1.2.1",
-            "caseless": "~0.12.0",
-            "combined-stream": "~1.0.5",
-            "extend": "~3.0.0",
-            "forever-agent": "~0.6.1",
-            "form-data": "~2.1.1",
-            "har-validator": "~4.2.1",
-            "hawk": "~3.1.3",
-            "http-signature": "~1.1.0",
-            "is-typedarray": "~1.0.0",
-            "isstream": "~0.1.2",
-            "json-stringify-safe": "~5.0.1",
-            "mime-types": "~2.1.7",
-            "oauth-sign": "~0.8.1",
-            "performance-now": "^0.2.0",
-            "qs": "~6.4.0",
-            "safe-buffer": "^5.0.1",
-            "stringstream": "~0.0.4",
-            "tough-cookie": "~2.3.0",
-            "tunnel-agent": "^0.6.0",
-            "uuid": "^3.0.0"
-          }
-        },
         "semver": {
           "version": "5.3.0",
           "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
@@ -7125,9 +7004,9 @@
       }
     },
     "node-sass": {
-      "version": "4.9.2",
-      "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.2.tgz",
-      "integrity": "sha512-LdxoJLZutx0aQXHtWIYwJKMj+9pTjneTcLWJgzf2XbGu0q5pRNqW5QvFCEdm3mc5rJOdru/mzln5d0EZLacf6g==",
+      "version": "4.9.3",
+      "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.9.3.tgz",
+      "integrity": "sha512-XzXyGjO+84wxyH7fV6IwBOTrEBe2f0a6SBze9QWWYR/cL74AcQUks2AsqcCZenl/Fp/JVbuEaLpgrLtocwBUww==",
       "dev": true,
       "requires": {
         "async-foreach": "^0.1.3",
@@ -7143,7 +7022,7 @@
         "meow": "^3.7.0",
         "mkdirp": "^0.5.1",
         "nan": "^2.10.0",
-        "node-gyp": "^3.3.1",
+        "node-gyp": "^3.8.0",
         "npmlog": "^4.0.0",
         "request": "2.87.0",
         "sass-graph": "^2.2.4",
@@ -7392,12 +7271,12 @@
       }
     },
     "original": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/original/-/original-1.0.1.tgz",
-      "integrity": "sha512-IEvtB5vM5ULvwnqMxWBLxkS13JIEXbakizMSo3yoPNPCIWzg8TG3Usn/UhXoZFM/m+FuEA20KdzPSFq/0rS+UA==",
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz",
+      "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==",
       "dev": true,
       "requires": {
-        "url-parse": "~1.4.0"
+        "url-parse": "^1.4.3"
       }
     },
     "os-browserify": {
@@ -7578,9 +7457,9 @@
       "dev": true
     },
     "path-parse": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
-      "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=",
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
+      "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
       "dev": true
     },
     "path-to-regexp": {
@@ -7622,9 +7501,9 @@
       }
     },
     "performance-now": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz",
-      "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+      "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
       "dev": true
     },
     "pify": {
@@ -7656,14 +7535,14 @@
       }
     },
     "popper.js": {
-      "version": "1.14.3",
-      "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.3.tgz",
-      "integrity": "sha1-FDj5jQRqz3tNeM1QK/QYrGTU8JU="
+      "version": "1.14.4",
+      "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.4.tgz",
+      "integrity": "sha1-juwdj/AqWjoVLdQ0FKFce3n9abY="
     },
     "portfinder": {
-      "version": "1.0.13",
-      "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz",
-      "integrity": "sha1-uzLs2HwnEErm7kS1o8y/Drsa7ek=",
+      "version": "1.0.16",
+      "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.16.tgz",
+      "integrity": "sha512-icBXCFQxzlK2PMepOM0QeEdPPFSLAaXXeuKOv5AClJlMy1oVCBrkDGJ12IZYesI/BF8mpeVco3vRCmgeBb4+hw==",
       "dev": true,
       "requires": {
         "async": "^1.5.2",
@@ -8418,9 +8297,9 @@
       "dev": true
     },
     "qs": {
-      "version": "6.4.0",
-      "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz",
-      "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=",
+      "version": "6.5.2",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
+      "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
       "dev": true
     },
     "query-string": {
@@ -8452,9 +8331,9 @@
       "dev": true
     },
     "randomatic": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.0.0.tgz",
-      "integrity": "sha512-VdxFOIEY3mNO5PtSRkkle/hPJDHvQhK21oa73K4yAc9qmp6N429gAyF1gZMOTMeS0/AYzaV/2Trcef+NaIonSA==",
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.0.tgz",
+      "integrity": "sha512-KnGPVE0lo2WoXxIZ7cPR8YBpiol4gsSuOwDSg410oHh80ZMp5EiypNqL2K4Z77vJn6lB5rap7IkAmcUlalcnBQ==",
       "dev": true,
       "requires": {
         "is-number": "^4.0.0",
@@ -8782,70 +8661,6 @@
         "tough-cookie": "~2.3.3",
         "tunnel-agent": "^0.6.0",
         "uuid": "^3.1.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
-        },
-        "aws-sign2": {
-          "version": "0.7.0",
-          "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
-          "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=",
-          "dev": true
-        },
-        "form-data": {
-          "version": "2.3.2",
-          "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz",
-          "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=",
-          "dev": true,
-          "requires": {
-            "asynckit": "^0.4.0",
-            "combined-stream": "1.0.6",
-            "mime-types": "^2.1.12"
-          }
-        },
-        "har-schema": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
-          "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=",
-          "dev": true
-        },
-        "har-validator": {
-          "version": "5.0.3",
-          "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
-          "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
-          "dev": true,
-          "requires": {
-            "ajv": "^5.1.0",
-            "har-schema": "^2.0.0"
-          }
-        },
-        "http-signature": {
-          "version": "1.2.0",
-          "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
-          "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
-          "dev": true,
-          "requires": {
-            "assert-plus": "^1.0.0",
-            "jsprim": "^1.2.2",
-            "sshpk": "^1.7.0"
-          }
-        },
-        "performance-now": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
-          "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=",
-          "dev": true
-        },
-        "qs": {
-          "version": "6.5.2",
-          "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
-          "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
-          "dev": true
-        }
       }
     },
     "require-directory": {
@@ -9323,15 +9138,6 @@
         }
       }
     },
-    "sntp": {
-      "version": "1.0.9",
-      "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz",
-      "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=",
-      "dev": true,
-      "requires": {
-        "hoek": "2.x.x"
-      }
-    },
     "sockjs": {
       "version": "0.3.19",
       "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz",
@@ -9507,14 +9313,6 @@
         "jsbn": "~0.1.0",
         "safer-buffer": "^2.0.2",
         "tweetnacl": "~0.14.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
-        }
       }
     },
     "static-extend": {
@@ -9615,12 +9413,6 @@
         "safe-buffer": "~5.1.0"
       }
     },
-    "stringstream": {
-      "version": "0.0.6",
-      "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz",
-      "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==",
-      "dev": true
-    },
     "strip-ansi": {
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
@@ -9664,15 +9456,15 @@
       },
       "dependencies": {
         "ajv": {
-          "version": "6.5.2",
-          "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.2.tgz",
-          "integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==",
+          "version": "6.5.3",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.3.tgz",
+          "integrity": "sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==",
           "dev": true,
           "requires": {
             "fast-deep-equal": "^2.0.1",
             "fast-json-stable-stringify": "^2.0.0",
             "json-schema-traverse": "^0.4.1",
-            "uri-js": "^4.2.1"
+            "uri-js": "^4.2.2"
           }
         },
         "fast-deep-equal": {
@@ -9688,9 +9480,9 @@
           "dev": true
         },
         "schema-utils": {
-          "version": "0.4.5",
-          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.5.tgz",
-          "integrity": "sha512-yYrjb9TX2k/J1Y5UNy3KYdZq10xhYcF8nMpAW6o3hy6Q8WSIEf9lJHG/ePnOBfziPM3fvQwfOwa13U/Fh8qTfA==",
+          "version": "0.4.7",
+          "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.4.7.tgz",
+          "integrity": "sha512-v/iwU6wvwGK8HbU9yi3/nhGzP0yGSuhQMzL6ySiec1FSrZZDkhm4noOSWzrNFo/jEc+SJY6jRTwuwbSXJPDUnQ==",
           "dev": true,
           "requires": {
             "ajv": "^6.1.0",
@@ -10145,9 +9937,9 @@
       "dev": true
     },
     "validate-npm-package-license": {
-      "version": "3.0.3",
-      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz",
-      "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==",
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
+      "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
       "dev": true,
       "requires": {
         "spdx-correct": "^3.0.0",
@@ -10175,14 +9967,6 @@
         "assert-plus": "^1.0.0",
         "core-util-is": "1.0.2",
         "extsprintf": "^1.2.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
-        }
       }
     },
     "vm-browserify": {
@@ -10308,15 +10092,15 @@
       },
       "dependencies": {
         "ajv": {
-          "version": "6.5.2",
-          "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.2.tgz",
-          "integrity": "sha512-hOs7GfvI6tUI1LfZddH82ky6mOMyTuY0mk7kE2pWpmhhUSkumzaTO5vbVwij39MdwPQWCV4Zv57Eo06NtL/GVA==",
+          "version": "6.5.3",
+          "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.3.tgz",
+          "integrity": "sha512-LqZ9wY+fx3UMiiPd741yB2pj3hhil+hQc8taf4o2QGRFpWgZ2V5C8HA165DY9sS3fJwsk7uT7ZlFEyC3Ig3lLg==",
           "dev": true,
           "requires": {
             "fast-deep-equal": "^2.0.1",
             "fast-json-stable-stringify": "^2.0.0",
             "json-schema-traverse": "^0.4.1",
-            "uri-js": "^4.2.1"
+            "uri-js": "^4.2.2"
           }
         },
         "camelcase": {